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) {