diff --git a/src/scene.cpp b/src/scene.cpp
index 49aaef9105423affd97ea9be5969afbacf7f21ad..6f841f3b9fd15de0ad33b387f4eed493efc39276 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -12,9 +12,9 @@
 #include <filesystem>
 #include <cmath>
 
-bool Scene::create(const SceneConfig& config, lava::device_ptr device, lava::staging& staging, uint32_t frame_count)
+bool Scene::create(const SceneConfig& config, lava::device_ptr device, uint32_t frame_count)
 {
-    this->create_dummy_textures(device, staging);
+    this->create_dummy_textures(device);
 
     std::map<std::string, SceneNodeIndex> node_indices;
 
@@ -89,6 +89,11 @@ bool Scene::create(const SceneConfig& config, lava::device_ptr device, lava::sta
         return false;
     }
 
+    if (!this->stage_textures(device))
+    {
+        return false;
+    }
+
     //NOTE: Recompute all transfromations for final scene bounds and matrices
     this->reset_transforms();
     
@@ -302,19 +307,39 @@ bool Scene::update(lava::delta delta_time, Headset::Ptr headset)
     return true;
 }
 
-bool Scene::stage(VkCommandBuffer command_buffer, lava::index frame)
+void Scene::write(lava::index frame)
 {
-    if (!this->stage_buffers(frame))
+    glsl::MeshData* mesh_data = (glsl::MeshData*)this->mesh_data_buffer[frame]->get_mapped_data();
+
+    for (uint32_t index = 0; index < this->meshes.size(); index++)
     {
-        return false;
+        const SceneMesh& mesh = this->meshes[index];
+
+        memcpy(&mesh_data[index], &mesh.data, sizeof(glsl::MeshData));
     }
 
-    if (!this->stage_textures(command_buffer, frame))
+    this->mesh_data_buffer[frame]->flush();
+
+    glsl::LightData* light_data = (glsl::LightData*)this->light_data_buffer[frame]->get_mapped_data();
+
+    for (uint32_t index = 0; index < this->lights.size(); index++)
     {
-        return false;
+        const SceneLight& light = this->lights[index];
+
+        memcpy(&light_data[index], &light.data, sizeof(glsl::LightData));
     }
 
-    return true;
+    this->light_data_buffer[frame]->flush();
+
+    if (this->exposure_changed)
+    {
+        //NOTE: The Buffer could be still in used during writing. Ignore this issure, since the exposure is not changed frequently.
+        glsl::LightParameter* light_parameter = (glsl::LightParameter*)this->light_parameter_buffer->get_mapped_data();
+        light_parameter->exposure = this->exposure;
+        this->light_parameter_buffer->flush();
+
+        this->exposure_changed = false;
+    }
 }
 
 void Scene::reset_animation()
@@ -496,17 +521,40 @@ void Scene::set_vertex_input_only_position(lava::graphics_pipeline* pipeline)
     pipeline->set_vertex_input_attributes({ { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, (uint32_t)(offsetof(lava::vertex, position)) } });
 }
 
-void Scene::create_dummy_textures(lava::device_ptr device, lava::staging& staging)
+void Scene::create_dummy_textures(lava::device_ptr device)
 {
     this->dummy_diffuse_texture = lava::create_default_texture(device, { 1, 1 }, glm::vec3(1.0, 1.0, 1.0), 1.0);  //Diffuse: (1.0, 1.0, 1.0) Opacity: 1.0
     this->dummy_specular_texture = lava::create_default_texture(device, { 1, 1 }, glm::vec3(0.0, 1.0, 0.0), 0.0); //Occlusion: 0.0 Roughness: 1.0 Metallic: 0.0
     this->dummy_normal_texture = lava::create_default_texture(device, { 1, 1 }, glm::vec3(0.5, 0.5, 0), 0.0);     //Normal: (0.5, 0.5) -> Vertex Normal
     this->dummy_emissive_texture = lava::create_default_texture(device, { 1, 1 }, glm::vec3(0.0, 0.0, 0), 0.0);   //Emissive: (0.0, 0.0, 0.0)
 
-    staging.add(this->dummy_diffuse_texture);
-    staging.add(this->dummy_specular_texture);
-    staging.add(this->dummy_normal_texture);
-    staging.add(this->dummy_emissive_texture);
+    SceneTexture diffuse_texture;
+    diffuse_texture.file_name = "dummy_diffuse_texture";
+    diffuse_texture.texture = this->dummy_diffuse_texture;
+    diffuse_texture.stage_dummy = true;
+
+    this->textures.push_back(diffuse_texture);
+
+    SceneTexture specular_texture;
+    specular_texture.file_name = "dummy_specular_texture";
+    specular_texture.texture = this->dummy_specular_texture;
+    specular_texture.stage_dummy = true;
+
+    this->textures.push_back(specular_texture);
+
+    SceneTexture normal_texture;
+    normal_texture.file_name = "dummy_normal_texture";
+    normal_texture.texture = this->dummy_normal_texture;
+    normal_texture.stage_dummy = true;
+
+    this->textures.push_back(normal_texture);
+
+    SceneTexture emissive_texture;
+    emissive_texture.file_name = "dummy_emissive_texture";
+    emissive_texture.texture = this->dummy_emissive_texture;
+    emissive_texture.stage_dummy = true;
+
+    this->textures.push_back(emissive_texture);
 }
 
 void Scene::create_default_light()
@@ -1590,64 +1638,63 @@ bool Scene::load_texture(const std::string& file_name, lava::device_ptr device,
     return true;
 }
 
-bool Scene::stage_buffers(lava::index frame)
+bool Scene::stage_textures(lava::device_ptr device)
 {
-    glsl::MeshData* mesh_data = (glsl::MeshData*)this->mesh_data_buffer[frame]->get_mapped_data();
+    VkCommandPoolCreateInfo pool_info;
+    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    pool_info.pNext = nullptr;
+    pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
+    pool_info.queueFamilyIndex = device->get_graphics_queue().family;
 
-    for (uint32_t index = 0; index < this->meshes.size(); index++)
-    {
-        const SceneMesh& mesh = this->meshes[index];
+    VkCommandPool command_pool = VK_NULL_HANDLE;
 
-        memcpy(&mesh_data[index], &mesh.data, sizeof(glsl::MeshData));
-    }
-
-    this->mesh_data_buffer[frame]->flush();
-
-    glsl::LightData* light_data = (glsl::LightData*)this->light_data_buffer[frame]->get_mapped_data();
-
-    for (uint32_t index = 0; index < this->lights.size(); index++)
+    if (vkCreateCommandPool(device->get(), &pool_info, lava::memory::alloc(), &command_pool) != VK_SUCCESS)
     {
-        const SceneLight& light = this->lights[index];
+        lava::log()->error("Can't create command pool for texture staging!");
 
-        memcpy(&light_data[index], &light.data, sizeof(glsl::LightData));
+        return false;
     }
 
-    this->light_data_buffer[frame]->flush();
+    VkCommandBufferAllocateInfo allocate_info;
+    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    allocate_info.pNext = nullptr;
+    allocate_info.commandPool = command_pool;
+    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    allocate_info.commandBufferCount = 1;
 
-    if (this->exposure_changed)
+    VkCommandBuffer command_buffer = VK_NULL_HANDLE;
+
+    if (vkAllocateCommandBuffers(device->get(), &allocate_info, &command_buffer) != VK_SUCCESS)
     {
-        //NOTE: The Buffer could be still in used during writing. Ignore this issure, since the exposure is not changed frequently.
-        glsl::LightParameter* light_parameter = (glsl::LightParameter*)this->light_parameter_buffer->get_mapped_data();
-        light_parameter->exposure = this->exposure;
-        this->light_parameter_buffer->flush();
+        lava::log()->error("Can't create command buffer for texture staging!");
 
-        this->exposure_changed = false;
+        return false;
     }
 
-    return true;
-}
+    VkCommandBufferBeginInfo begin_info;
+    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    begin_info.pNext = nullptr;
+    begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    begin_info.pInheritanceInfo = nullptr;
 
-bool Scene::stage_textures(VkCommandBuffer command_buffer, lava::index frame)
-{
-    for (SceneTexture& scene_texture : this->textures)
+    if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS)
     {
-        if (scene_texture.stage_active && scene_texture.stage_frame == frame)
-        {
-            scene_texture.stage_buffer->destroy();
-            scene_texture.stage_buffer = nullptr;
+        lava::log()->error("Can't begin command buffer during texture staging!");
 
-            scene_texture.stage_active = false;
-            scene_texture.stage_frame = 0;
-            scene_texture.stage_levels = 0;
-        }
+        return false;
     }
 
-    for (SceneTexture& scene_texture : this->textures)
+    for (const SceneTexture& scene_texture : this->textures)
     {
         lava::texture::ptr texture = scene_texture.texture;
         lava::buffer::ptr stage_buffer = scene_texture.stage_buffer;
 
-        if (!scene_texture.stage_active && stage_buffer != nullptr)
+        if (scene_texture.stage_dummy)
+        {
+            texture->stage(command_buffer);
+        }
+
+        else if (stage_buffer != nullptr)
         {
             VkImageMemoryBarrier begin_barrier;
             begin_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -1781,9 +1828,56 @@ bool Scene::stage_textures(VkCommandBuffer command_buffer, lava::index frame)
             end_barrier.subresourceRange = texture->get_image()->get_subresource_range();
 
             vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &end_barrier);
+        }        
+    }
 
-            scene_texture.stage_active = true;
-            scene_texture.stage_frame = frame;
+    if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS)
+    {
+        lava::log()->error("Can't end command buffer during texture staging!");
+
+        return false;
+    }
+
+    VkSubmitInfo submit_info;
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.pNext = nullptr;
+    submit_info.waitSemaphoreCount = 0;
+    submit_info.pWaitSemaphores = nullptr;
+    submit_info.pWaitDstStageMask = nullptr;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &command_buffer;
+    submit_info.signalSemaphoreCount = 0;
+    submit_info.pSignalSemaphores = nullptr;
+
+    if (vkQueueSubmit(device->get_graphics_queue().vk_queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS)
+    {
+        lava::log()->error("Can't submit command buffer for texture staging!");
+
+        return false;
+    }
+
+    if (vkDeviceWaitIdle(device->get()) != VK_SUCCESS)
+    {
+        lava::log()->error("Can't wait for texture staging completion!");
+
+        return false;
+    }
+
+    vkDestroyCommandPool(device->get(), command_pool, lava::memory::alloc());
+
+    for (SceneTexture& scene_texture : this->textures)
+    {
+        if (scene_texture.stage_dummy)
+        {
+            scene_texture.texture->destroy_upload_buffer();
+            scene_texture.stage_dummy = false;
+        }
+
+        else if (scene_texture.stage_buffer != nullptr)
+        {
+            scene_texture.stage_buffer->destroy();
+            scene_texture.stage_buffer = nullptr;
+            scene_texture.stage_levels = 0;
         }
     }
 
diff --git a/src/scene.hpp b/src/scene.hpp
index 591b0d261a98b96a5434fc05682c917b87821faa..00088fc6920ac8e20983724c83fdf3eb2586c523 100644
--- a/src/scene.hpp
+++ b/src/scene.hpp
@@ -113,10 +113,9 @@ struct SceneTexture
     std::string file_name;
     lava::texture::ptr texture;
 
-    bool stage_active = false;
-    uint32_t stage_frame = 0;
     uint32_t stage_levels = 0;
     lava::buffer::ptr stage_buffer;
+    bool stage_dummy = false;
 };
 
 struct SceneAnimationChannel
@@ -143,12 +142,12 @@ public:
 public:
     Scene() = default;
     
-    bool create(const SceneConfig& config, lava::device_ptr device, lava::staging& staging, uint32_t frame_count);
+    bool create(const SceneConfig& config, lava::device_ptr device, uint32_t frame_count);
     void destroy();
 
     bool interface();
     bool update(lava::delta delta_time, Headset::Ptr headset);
-    bool stage(VkCommandBuffer command_buffer, lava::index frame);
+    void write(lava::index frame);
 
     void reset_animation();
     void set_animation_active(bool active);
@@ -184,7 +183,7 @@ public:
     static void set_vertex_input_only_position(lava::graphics_pipeline* pipeline);
 
 private:
-    void create_dummy_textures(lava::device_ptr device, lava::staging& staging);
+    void create_dummy_textures(lava::device_ptr device);
     void create_default_light();
 
     bool create_descriptor_layouts(lava::device_ptr device, uint32_t frame_count);
@@ -205,8 +204,7 @@ private:
     bool load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, lava::device_ptr device, lava::texture::ptr& texture);
     bool load_texture(const std::string& file_name, lava::device_ptr device, bool use_float, bool use_mipmaps, lava::texture::ptr& texture);
 
-    bool stage_buffers(lava::index frame);
-    bool stage_textures(VkCommandBuffer command_buffer, lava::index frame);
+    bool stage_textures(lava::device_ptr device);
 
     void compute_scene_bounds();
     void compute_mesh_bounds(SceneMesh& mesh, const glm::mat4& local_to_world);
diff --git a/src/utility/indirect_cache.cpp b/src/utility/indirect_cache.cpp
index 1c0de87ec877d9a65a899bb6a15b24a6af82e5a1..2ef468dd9bb295b2de133b5572643ecec749d4db 100644
--- a/src/utility/indirect_cache.cpp
+++ b/src/utility/indirect_cache.cpp
@@ -30,7 +30,7 @@ bool IndirectCache::create(Scene::Ptr scene, const IndirectCacheSettings& settin
         return false;
     }
 
-    if (!this->create_buffers(device, settings))
+    if (!this->create_buffers(device))
     {
         return false;
     }
@@ -252,16 +252,21 @@ void IndirectCache::compute_indirect(VkCommandBuffer command_buffer, lava::index
     uint32_t batch_count = this->propagation_iterations / batch_size;
     uint32_t batch_rest = this->propagation_iterations % batch_size;
 
+    lava::log()->info("Computing Indirect Cache: 0%");
+
     for (uint32_t index = 0; index < batch_count; index++)
     {
-        lava::log()->debug("{}", index);
+        this->submit_propagation(batch_size);
 
-        this->submit_propagation(batch_size);    
+        uint32_t progress = (((index + 1) * batch_size * 100) / this->propagation_iterations);
+        lava::log()->info("Computing Indirect Cache: {}%", progress);
     }
 
     if (batch_rest > 0)
     {
         this->submit_propagation(batch_rest);
+
+        lava::log()->info("Computing Indirect Cache: 100%");
     }
     
     std::vector<VkImageMemoryBarrier> final_barriers = IndirectCache::build_barriers(3, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
@@ -304,11 +309,36 @@ bool IndirectCache::compute_domain(Scene::Ptr scene, const IndirectCacheSettings
 
     const glm::uvec3 work_group_size = glm::uvec3(16, 16, 2);
 
-    this->domain_indirect_resolution = glm::uvec3(glm::max(glm::ceil(scene_size / settings.cell_size), glm::vec3(1.0f)));
+    this->domain_cell_size = settings.cell_size;
+    this->domain_indirect_resolution = glm::uvec3(glm::max(glm::ceil(scene_size / this->domain_cell_size), glm::vec3(1.0f)));
     this->domain_geometry_resolution = this->domain_indirect_resolution + glm::uvec3(1);
     this->domain_voxel_resolution = this->domain_geometry_resolution * settings.voxel_resolution_scale;
-    this->domain_min = scene_center - 0.5f * settings.cell_size * glm::vec3(this->domain_indirect_resolution);
-    this->domain_max = scene_center + 0.5f * settings.cell_size * glm::vec3(this->domain_indirect_resolution);
+
+    uint32_t indirect_pixel_count = this->domain_indirect_resolution.x * this->domain_indirect_resolution.y * this->domain_indirect_resolution.z;
+    uint32_t geometry_pixel_count = this->domain_geometry_resolution.x * this->domain_geometry_resolution.y * this->domain_geometry_resolution.z;
+    uint32_t memory_size = (indirect_pixel_count * 9 * sizeof(glm::vec4) + geometry_pixel_count * 2 * sizeof(glm::vec4)) / (1024 * 1024); // In MiB
+
+    if (memory_size > settings.memory_limit)
+    {
+        float factor_scene = 11 * (scene_size.x * scene_size.y * scene_size.z) * sizeof(glm::vec4);
+        float factor_limit = settings.memory_limit * 1024 * 1024;
+
+        this->domain_cell_size = std::cbrt(factor_scene / factor_limit);
+
+        this->domain_indirect_resolution = glm::uvec3(glm::max(glm::ceil(scene_size / this->domain_cell_size), glm::vec3(1.0f)));
+        this->domain_geometry_resolution = this->domain_indirect_resolution + glm::uvec3(1);
+        this->domain_voxel_resolution = this->domain_geometry_resolution * settings.voxel_resolution_scale;
+
+        lava::log()->warn("Indirect Cache exceed Memory Limit. Reducing Cell Size to {} Meters!", this->domain_cell_size);
+    }
+
+    else
+    {
+        lava::log()->info("Indirect Cache Size: {} MiB", memory_size);
+    }
+
+    this->domain_min = scene_center - 0.5f * this->domain_cell_size * glm::vec3(this->domain_indirect_resolution);
+    this->domain_max = scene_center + 0.5f * this->domain_cell_size * glm::vec3(this->domain_indirect_resolution);
     this->domain_work_groups = this->domain_indirect_resolution / work_group_size;
     
     if ((this->domain_indirect_resolution.x % work_group_size.x) > 0)
@@ -380,11 +410,11 @@ bool IndirectCache::create_fence(lava::device_ptr device)
     return true;
 }
 
-bool IndirectCache::create_buffers(lava::device_ptr device, const IndirectCacheSettings& settings)
+bool IndirectCache::create_buffers(lava::device_ptr device)
 {
     glsl::IndirectDomain indirect_domain;
     indirect_domain.indirect_resolution = this->domain_indirect_resolution;
-    indirect_domain.cell_size = settings.cell_size;
+    indirect_domain.cell_size = this->domain_cell_size;
     indirect_domain.geometry_resolution = this->domain_geometry_resolution;
     indirect_domain.padding1 = 0;
     indirect_domain.min = this->domain_min;
diff --git a/src/utility/indirect_cache.hpp b/src/utility/indirect_cache.hpp
index e6cebb150b30e17e7186ce57dbd70a06ba7c4762..055b35649175c06257fde3957af06ed3a8dec01e 100644
--- a/src/utility/indirect_cache.hpp
+++ b/src/utility/indirect_cache.hpp
@@ -44,8 +44,9 @@
 struct IndirectCacheSettings
 {
     uint32_t capture_resolution = 1024;
-    uint32_t voxel_resolution_scale = 1; //Needs to be greater or equal to one
-    float cell_size = 0.5f; //Where cell size is in meters
+    uint32_t voxel_resolution_scale = 1;    // Needs to be greater or equal to one
+    float cell_size = 1.0f;                 // Where cell size is in meters
+    uint32_t memory_limit = 512;            // Where memory limit is in MiB
 };
 
 class IndirectCache
@@ -71,7 +72,7 @@ private:
 
     bool create_command_buffer(lava::device_ptr device);
     bool create_fence(lava::device_ptr device);
-    bool create_buffers(lava::device_ptr device, const IndirectCacheSettings& settings);
+    bool create_buffers(lava::device_ptr device);
     bool create_images(lava::device_ptr device, const IndirectCacheSettings& settings);
     bool create_samplers(lava::device_ptr device);
     bool create_descriptors(lava::device_ptr device);
@@ -103,6 +104,7 @@ private:
 
     uint32_t propagation_iterations = 0;
 
+    float domain_cell_size = 1.0f;
     glm::vec3 domain_min = glm::vec3(0.0f);
     glm::vec3 domain_max = glm::vec3(0.0f);
     glm::uvec3 domain_indirect_resolution = glm::uvec3(0);
diff --git a/src/vr_application.cpp b/src/vr_application.cpp
index e387839c22e97cb40246d1db9991800e7567c8d1..4c1acab66e7c44fbb1dfbf9487fc60dc80a41a01 100644
--- a/src/vr_application.cpp
+++ b/src/vr_application.cpp
@@ -337,7 +337,7 @@ bool VRApplication::on_create()
 
     this->scene = make_scene();
 
-    if (!this->scene->create(config, this->app->device, this->app->staging, this->get_frame_count()))
+    if (!this->scene->create(config, this->app->device, this->get_frame_count()))
     {
         return false;
     }
@@ -700,13 +700,7 @@ bool VRApplication::on_render(VkCommandBuffer command_buffer, lava::index frame)
     this->pass_timer->next_frame(command_buffer, frame, this->app->device);
 
     this->stereo_transform->write(frame);
-
-    if (!this->scene->stage(command_buffer, frame))
-    {
-        lava::log()->error("Error during scene stage!");
-
-        return false;
-    }
+    this->scene->write(frame);
 
     if (!this->cache_filled)
     {