diff --git a/liblava/resource/texture.hpp b/liblava/resource/texture.hpp index 7990d0854f119dd63df35fdd8c70e0e6207a8b03..93632755df85fa682cacf745ffd3dfa9e80f9ab4 100644 --- a/liblava/resource/texture.hpp +++ b/liblava/resource/texture.hpp @@ -72,6 +72,10 @@ namespace lava { return img ? img->get_format() : VK_FORMAT_UNDEFINED; } + const layer::list& get_layers() const { + return layers; + } + private: image::ptr img; diff --git a/src/scene.cpp b/src/scene.cpp index 099625ecbc2cff7f3a25ee77ebdc5878b14dbdc3..c8882f3a6d7e7354a941cdc9c3af0d209ff88392 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -8,6 +8,7 @@ #include <glm/gtx/matrix_operation.hpp> #include <imgui.h> #include <stb_image.h> +#include <gli/gli.hpp> #include <filesystem> #include <cmath> @@ -19,7 +20,7 @@ bool Scene::create(const SceneConfig& config, lava::device_ptr device, lava::sta if (!config.scene_file.empty()) { - if (!this->load_scene(config.scene_file, config.scene_unit, config.scene_orientation, device, staging, node_indices)) + if (!this->load_scene(config.scene_file, config.scene_unit, config.scene_orientation, device, node_indices)) { return false; } @@ -34,7 +35,7 @@ bool Scene::create(const SceneConfig& config, lava::device_ptr device, lava::sta if (!config.controller_left_file.empty()) { - if (!this->load_controller(config.controller_left_file, config.controller_left_unit, config.controller_left_orientation, device, staging, this->controller_left, node_indices)) + if (!this->load_controller(config.controller_left_file, config.controller_left_unit, config.controller_left_orientation, device, this->controller_left, node_indices)) { return false; } @@ -44,7 +45,7 @@ bool Scene::create(const SceneConfig& config, lava::device_ptr device, lava::sta if (!config.controller_right_file.empty()) { - if (!this->load_controller(config.controller_right_file, config.controller_right_unit, config.controller_right_orientation, device, staging, this->controller_right, node_indices)) + if (!this->load_controller(config.controller_right_file, config.controller_right_unit, config.controller_right_orientation, device, this->controller_right, node_indices)) { return false; } @@ -57,7 +58,7 @@ bool Scene::create(const SceneConfig& config, lava::device_ptr device, lava::sta //NOTE: Need to compute scene bounds for sky-sphere this->reset_transforms(); - if (!this->load_sky_sphere(config.sky_sphere_file, config.sky_sphere_rings, config.sky_sphere_segments, device, staging)) + if (!this->load_sky_sphere(config.sky_sphere_file, config.sky_sphere_rings, config.sky_sphere_segments, device)) { return false; } @@ -301,38 +302,16 @@ bool Scene::update(lava::delta delta_time, Headset::Ptr headset) return true; } -bool Scene::write(lava::index frame) +bool Scene::stage(VkCommandBuffer command_buffer, lava::index 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++) + if (!this->stage_buffers(frame)) { - const SceneMesh& mesh = this->meshes[index]; - - 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++) - { - const SceneLight& light = this->lights[index]; - - memcpy(&light_data[index], &light.data, sizeof(glsl::LightData)); + return false; } - this->light_data_buffer[frame]->flush(); - - if (this->exposure_changed) + if (!this->stage_textures(command_buffer, frame)) { - //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; + return false; } return true; @@ -479,6 +458,11 @@ const std::vector<SceneMaterial>& Scene::get_materials() const return this->materials; } +const std::vector<SceneTexture>& Scene::get_textures() const +{ + return this->textures; +} + const std::vector<SceneAnimation>& Scene::get_animations() const { return this->animations; @@ -827,7 +811,7 @@ bool Scene::create_mesh_buffer(lava::device_ptr device, uint32_t frame_count) return true; } -bool Scene::load_scene(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, lava::staging& staging, std::map<std::string, SceneNodeIndex>& node_indices) +bool Scene::load_scene(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, std::map<std::string, SceneNodeIndex>& node_indices) { uint32_t post_processes = 0; float scale = 1.0f; @@ -860,7 +844,7 @@ bool Scene::load_scene(const std::string& file_name, SceneUnit unit, SceneOrient this->materials.reserve(scene->mNumMaterials); this->animations.reserve(scene->mNumAnimations); - if (!this->load_materials(scene, file_name, device, staging)) + if (!this->load_materials(scene, file_name, device)) { return false; } @@ -893,7 +877,7 @@ bool Scene::load_scene(const std::string& file_name, SceneUnit unit, SceneOrient return true; } -bool Scene::load_controller(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, lava::staging& staging, SceneNodeIndex& node_index, std::map<std::string, SceneNodeIndex>& node_indices) +bool Scene::load_controller(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, SceneNodeIndex& node_index, std::map<std::string, SceneNodeIndex>& node_indices) { uint32_t post_processes = 0; float scale = 1.0f; @@ -926,7 +910,7 @@ bool Scene::load_controller(const std::string& file_name, SceneUnit unit, SceneO this->meshes.reserve(scene->mNumMeshes); this->materials.reserve(scene->mNumMaterials); - if (!this->load_materials(scene, file_name, device, staging)) + if (!this->load_materials(scene, file_name, device)) { return false; } @@ -946,68 +930,17 @@ bool Scene::load_controller(const std::string& file_name, SceneUnit unit, SceneO return true; } -bool Scene::load_sky_sphere(const std::string& file_name, uint32_t ring_count, uint32_t segment_count, lava::device_ptr device, lava::staging& staging) +bool Scene::load_sky_sphere(const std::string& file_name, uint32_t ring_count, uint32_t segment_count, lava::device_ptr device) { lava::log()->info("Loading sky-sphere file '{}'", file_name.c_str()); - lava::file file(file_name.c_str()); - - int32_t width = 0; - int32_t height = 0; - float* pixel_data = nullptr; - - if (file.opened()) - { - lava::unique_data image_data(file.get_size(), false); - - if (!image_data.allocate()) - { - lava::log()->error("Can't allocate memory for sky-sphere image!"); - - return false; - } - - if (lava::file_error(file.read(image_data.ptr))) - { - lava::log()->error("Can't read image for sky-sphere!"); - - return false; - } - - pixel_data = stbi_loadf_from_memory((const stbi_uc*)image_data.ptr, image_data.size, &width, &height, nullptr, STBI_rgb_alpha); - } - - else - { - pixel_data = stbi_loadf(file_name.c_str(), &width, &height, nullptr, STBI_rgb_alpha); - } - - if (pixel_data == nullptr) - { - lava::log()->error("Faild to load sky-sphere file '{}'", file_name.c_str()); - - return false; - } - - this->sky_emissive_texture = lava::make_texture(); - - if (!this->sky_emissive_texture->create(device, glm::uvec2(width, height), VK_FORMAT_R32G32B32A32_SFLOAT)) - { - lava::log()->error("Can't create texture for sky-sphere!"); - - return false; - } - - if (!this->sky_emissive_texture->upload(pixel_data, width * height * 4 * sizeof(float))) + if (!this->load_texture(file_name, device, true, false, this->sky_emissive_texture)) { - lava::log()->error("Can't upload texture for sky-sphere!!"); + lava::log()->error("Faild to load sky-sphere '{}'", file_name.c_str()); return false; } - stbi_image_free(pixel_data); - staging.add(this->sky_emissive_texture); - uint32_t sky_material_index = this->materials.size(); SceneMaterial& sky_material = this->materials.emplace_back(); sky_material.diffuse = this->dummy_diffuse_texture; @@ -1358,7 +1291,7 @@ bool Scene::load_meshes(const aiScene* scene, float scale, uint32_t base_materia return true; } -bool Scene::load_materials(const aiScene* scene, const std::string& base_name, lava::device_ptr device, lava::staging& staging) +bool Scene::load_materials(const aiScene* scene, const std::string& base_name, lava::device_ptr device) { for (uint32_t index = 0; index < scene->mNumMaterials; index++) { @@ -1393,7 +1326,7 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l material_data.padding4 = glm::mat4(0); material_data.padding5 = glm::mat4(0); - if (!this->load_texture(material, base_name, aiTextureType_DIFFUSE, device, staging, scene_material.diffuse)) + if (!this->load_texture(material, base_name, aiTextureType_DIFFUSE, device, scene_material.diffuse)) { scene_material.diffuse = this->dummy_diffuse_texture; @@ -1401,7 +1334,7 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l material_data.opacity = glm::clamp(opacity, 0.0f, 1.0f); } - if (!this->load_texture(material, base_name, aiTextureType_SPECULAR, device, staging, scene_material.specular)) + if (!this->load_texture(material, base_name, aiTextureType_SPECULAR, device, scene_material.specular)) { scene_material.specular = this->dummy_specular_texture; @@ -1409,7 +1342,7 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l material_data.metallic = glm::clamp(reflectivity, 0.0f, 1.0f); } - if (!this->load_texture(material, base_name, aiTextureType_NORMALS, device, staging, scene_material.normal)) + if (!this->load_texture(material, base_name, aiTextureType_NORMALS, device, scene_material.normal)) { scene_material.normal = this->dummy_normal_texture; } @@ -1418,7 +1351,7 @@ bool Scene::load_materials(const aiScene* scene, const std::string& base_name, l return true; } -bool Scene::load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, lava::device_ptr device, lava::staging& staging, lava::texture::ptr& texture) +bool Scene::load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, lava::device_ptr device, lava::texture::ptr& texture) { aiString texture_path; @@ -1437,28 +1370,412 @@ bool Scene::load_texture(const aiMaterial* material, const std::string& base_nam } std::filesystem::path base_path = std::filesystem::path(base_name).parent_path(); - std::string path_string = (base_path / texture_path.C_Str()).string(); - std::replace(path_string.begin(), path_string.end(), '\\', '/'); + std::string file_name = (base_path / texture_path.C_Str()).string(); + std::replace(file_name.begin(), file_name.end(), '\\', '/'); + + if (!this->load_texture(file_name, device, false, true, texture)) + { + lava::log()->warn("Faild to load texture file '{}'. Using dummy texture instead.", file_name.c_str()); - lava::log()->info("Loading texture file '{}'", path_string.c_str()); + return false; + } - texture = lava::load_texture(device, path_string, VK_FORMAT_UNDEFINED); + return true; +} - if (texture == nullptr) +bool Scene::load_texture(const std::string& file_name, lava::device_ptr device, bool use_float, bool use_mipmaps, lava::texture::ptr& texture) +{ + for (const SceneTexture& scene_texture : this->textures) + { + if (scene_texture.file_name == file_name) + { + texture = scene_texture.texture; + + return true; + } + } + + lava::log()->info("Loading texture file '{}'", file_name.c_str()); + + lava::file file(file_name.c_str()); + + if (!file.opened()) { - lava::log()->warn("Faild to load texture file '{}'. Using dummy texture instead.", path_string.c_str()); + lava::log()->error("Can't open texture: " + file_name + " !"); return false; } - if (texture->get_size() == glm::uvec2(1, 1)) + lava::unique_data image_data(file.get_size(), false); + + if (!image_data.allocate()) { - lava::log()->warn("Loaded texture '{}' has invalid dimensions. Using dummy texture instead.", path_string.c_str()); + lava::log()->error("Can't allocate memory for texture: " + file_name + " !"); return false; } - staging.add(texture); + if (lava::file_error(file.read(image_data.ptr))) + { + lava::log()->error("Can't read texture: " + file_name + " !"); + + return false; + } + + VkFormat format = VK_FORMAT_UNDEFINED; + int32_t width = 0; + int32_t height = 0; + lava::texture::layer layer; + + lava::buffer::ptr stage_buffer = lava::make_buffer(); + uint32_t stage_levels = 0; + + bool use_gli = lava::extension(file_name.c_str(), { "DDS", "KTX", "KMG" }); + bool use_stbi = lava::extension(file_name.c_str(), { "JPG", "PNG", "TGA", "BMP", "PSD", "GIF", "HDR", "PIC" }); + + if (use_gli) + { + gli::texture texture = gli::load(image_data.ptr, image_data.size); + + if(texture.empty()) + { + lava::log()->error("Can't load texture: " + file_name + " !"); + + return false; + } + + switch (texture.format()) + { + case gli::FORMAT_RGBA_DXT1_UNORM_BLOCK8: + format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + break; + case gli::FORMAT_RGBA_DXT5_UNORM_BLOCK16: + format = VK_FORMAT_BC3_UNORM_BLOCK; + break; + case gli::FORMAT_RG_ATI2N_UNORM_BLOCK16: + format = VK_FORMAT_BC5_UNORM_BLOCK; + break; + default: + lava::log()->error("Unkown texture format. Can't load texture: " + file_name + " !"); + return false; + } + + width = texture.extent().x; + height = texture.extent().y; + stage_levels = (use_mipmaps) ? texture.levels() : 1; + + uint32_t data_size = 0; + + for (uint32_t index = 0; index < stage_levels; index++) + { + lava::texture::mip_level level; + level.extent = texture.extent(index); + level.size = texture.size(index); + + layer.levels.push_back(level); + data_size += level.size; + } + + if (!stage_buffer->create_mapped(device, texture.data(), data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)) + { + lava::log()->error("Can't create staging buffer for texture: " + file_name + " !"); + + return false; + } + } + + else if (use_stbi) + { + uint8_t* data_pointer = nullptr; + uint32_t data_bitdepth = 0; + + if (use_float) + { + format = VK_FORMAT_R32G32B32A32_SFLOAT; + + data_pointer = (uint8_t*) stbi_loadf_from_memory((const stbi_uc*) image_data.ptr, image_data.size, &width, &height, nullptr, STBI_rgb_alpha); + data_bitdepth = 4 * sizeof(float); + } + + else + { + format = VK_FORMAT_R8G8B8A8_SRGB; + + data_pointer = (uint8_t*) stbi_load_from_memory((const stbi_uc*) image_data.ptr, image_data.size, &width, &height, nullptr, STBI_rgb_alpha); + data_bitdepth = 4 * sizeof(uint8_t); + } + + if (data_pointer == nullptr) + { + lava::log()->error("Can't load texture: " + file_name + " !"); + + return false; + } + + uint32_t data_size = width * height * data_bitdepth; + stage_levels = 1; + + if (!stage_buffer->create_mapped(device, data_pointer, data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)) + { + lava::log()->error("Can't create staging buffer for texture: " + file_name + " !"); + stbi_image_free(data_pointer); + + return false; + } + + stbi_image_free(data_pointer); + + if (use_mipmaps) + { + uint32_t mipmap_width = width; + uint32_t mipmap_height = height; + + while (mipmap_width > 1 || mipmap_width > 1) + { + lava::texture::mip_level level; + level.extent = glm::uvec2(mipmap_width, mipmap_height); + level.size = mipmap_width * mipmap_height * data_bitdepth; + + layer.levels.push_back(level); + + mipmap_width = glm::max((uint32_t)1, mipmap_width >> 1); + mipmap_height = glm::max((uint32_t)1, mipmap_height >> 1); + } + } + + else + { + lava::texture::mip_level level; + level.extent = glm::uvec2(width, height); + level.size = width * height * data_bitdepth; + + layer.levels.push_back(level); + } + } + + else + { + lava::log()->error("Unsupported texture format. Can't load texture: " + file_name + " !"); + + return false; + } + + texture = lava::make_texture(); + + if(!texture->create(device, glm::uvec2(width, height), format, {layer}, lava::texture_type::tex_2d)) + { + lava::log()->error("Can't create texture: " + file_name + " !"); + + return false; + } + + SceneTexture scene_texture; + scene_texture.file_name = file_name; + scene_texture.texture = texture; + scene_texture.stage_levels = stage_levels; + scene_texture.stage_buffer = stage_buffer; + + this->textures.push_back(scene_texture); + + return true; +} + +bool Scene::stage_buffers(lava::index 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++) + { + const SceneMesh& mesh = this->meshes[index]; + + 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++) + { + const SceneLight& light = this->lights[index]; + + memcpy(&light_data[index], &light.data, sizeof(glsl::LightData)); + } + + 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; + } + + return true; +} + +bool Scene::stage_textures(VkCommandBuffer command_buffer, lava::index frame) +{ + for (SceneTexture& scene_texture : this->textures) + { + if (scene_texture.stage_active && scene_texture.stage_frame == frame) + { + scene_texture.stage_buffer->destroy(); + scene_texture.stage_buffer = nullptr; + + scene_texture.stage_active = false; + scene_texture.stage_frame = 0; + scene_texture.stage_levels = 0; + } + } + + for (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) + { + VkImageMemoryBarrier begin_barrier; + begin_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + begin_barrier.pNext = nullptr; + begin_barrier.srcAccessMask = 0; + begin_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + begin_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + begin_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + begin_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + begin_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + begin_barrier.image = texture->get_image()->get(); + begin_barrier.subresourceRange = texture->get_image()->get_subresource_range(); + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &begin_barrier); + + const std::vector<lava::texture::mip_level>& levels = texture->get_layers().front().levels; + uint32_t stage_levels = scene_texture.stage_levels; + uint32_t total_levels = texture->get_image()->get_info().mipLevels; + + std::vector<VkBufferImageCopy> regions; + uint32_t buffer_offset = 0; + + for (uint32_t index = 0; index < scene_texture.stage_levels; index++) + { + VkImageSubresourceLayers subresource; + subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresource.mipLevel = index; + subresource.baseArrayLayer = 0; + subresource.layerCount = 1; + + VkOffset3D offset; + offset.x = 0; + offset.y = 0; + offset.z = 0; + + VkExtent3D extent; + extent.width = levels[index].extent.x; + extent.height = levels[index].extent.y; + extent.depth = 1; + + VkBufferImageCopy region; + region.bufferOffset = buffer_offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource = subresource; + region.imageOffset = offset; + region.imageExtent = extent; + + regions.push_back(region); + buffer_offset += levels[index].size; + } + + vkCmdCopyBufferToImage(command_buffer, stage_buffer->get(), texture->get_image()->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions.size(), regions.data()); + + for (uint32_t index = stage_levels; index < total_levels; index++) + { + glm::uvec2 src_size = levels[index - 1].extent; + glm::uvec2 dst_size = levels[index].extent; + + VkImageMemoryBarrier src_begin_barrier; + src_begin_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + src_begin_barrier.pNext = nullptr; + src_begin_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + src_begin_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + src_begin_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + src_begin_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + src_begin_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + src_begin_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + src_begin_barrier.image = texture->get_image()->get(); + src_begin_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + src_begin_barrier.subresourceRange.baseMipLevel = index - 1; + src_begin_barrier.subresourceRange.levelCount = 1; + src_begin_barrier.subresourceRange.baseArrayLayer = 0; + src_begin_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &src_begin_barrier); + + VkImageBlit region; + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.mipLevel = index - 1; + region.srcSubresource.baseArrayLayer = 0; + region.srcSubresource.layerCount = 1; + region.srcOffsets[0].x = 0; + region.srcOffsets[0].y = 0; + region.srcOffsets[0].z = 0; + region.srcOffsets[1].x = src_size.x; + region.srcOffsets[1].y = src_size.y; + region.srcOffsets[1].z = 1; + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.dstSubresource.mipLevel = index; + region.dstSubresource.baseArrayLayer = 0; + region.dstSubresource.layerCount = 1; + region.dstOffsets[0].x = 0; + region.dstOffsets[0].y = 0; + region.dstOffsets[0].z = 0; + region.dstOffsets[1].x = dst_size.x; + region.dstOffsets[1].y = dst_size.y; + region.dstOffsets[1].z = 1; + + vkCmdBlitImage(command_buffer, texture->get_image()->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture->get_image()->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, VK_FILTER_LINEAR); + + VkImageMemoryBarrier src_end_barrier; + src_end_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + src_end_barrier.pNext = nullptr; + src_end_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + src_end_barrier.dstAccessMask = 0; + src_end_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + src_end_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + src_end_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + src_end_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + src_end_barrier.image = texture->get_image()->get(); + src_end_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + src_end_barrier.subresourceRange.baseMipLevel = index - 1; + src_end_barrier.subresourceRange.levelCount = 1; + src_end_barrier.subresourceRange.baseArrayLayer = 0; + src_end_barrier.subresourceRange.layerCount = 1; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &src_end_barrier); + } + + VkImageMemoryBarrier end_barrier; + end_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + end_barrier.pNext = nullptr; + end_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + end_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + end_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + end_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + end_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + end_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + end_barrier.image = texture->get_image()->get(); + 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; + } + } return true; } diff --git a/src/scene.hpp b/src/scene.hpp index a53d398aab611caa1c9b0145f14754afeb304310..591b0d261a98b96a5434fc05682c917b87821faa 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -108,6 +108,17 @@ struct SceneMaterial VkDescriptorSet descriptor_set = VK_NULL_HANDLE; }; +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; +}; + struct SceneAnimationChannel { SceneNodeIndex node_index = INVALID_NODE; @@ -137,7 +148,7 @@ public: bool interface(); bool update(lava::delta delta_time, Headset::Ptr headset); - bool write(lava::index frame); + bool stage(VkCommandBuffer command_buffer, lava::index frame); void reset_animation(); void set_animation_active(bool active); @@ -163,6 +174,7 @@ public: const std::vector<SceneMesh>& get_meshes() const; const std::vector<SceneLight>& get_lights() const; const std::vector<SceneMaterial>& get_materials() const; + const std::vector<SceneTexture>& get_textures() const; const std::vector<SceneAnimation>& get_animations() const; const glm::vec3& get_scene_min() const; @@ -180,17 +192,21 @@ private: bool create_light_buffer(lava::device_ptr device, uint32_t frame_count); bool create_mesh_buffer(lava::device_ptr device, uint32_t frame_count); - bool load_scene(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, lava::staging& staging, std::map<std::string, SceneNodeIndex>& node_indices); - bool load_controller(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, lava::staging& staging, SceneNodeIndex& node_index, std::map<std::string, SceneNodeIndex>& node_indices); - bool load_sky_sphere(const std::string& file_name, uint32_t ring_count, uint32_t segment_count, lava::device_ptr device, lava::staging& staging); + bool load_scene(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, std::map<std::string, SceneNodeIndex>& node_indices); + bool load_controller(const std::string& file_name, SceneUnit unit, SceneOrientation orientation, lava::device_ptr device, SceneNodeIndex& node_index, std::map<std::string, SceneNodeIndex>& node_indices); + bool load_sky_sphere(const std::string& file_name, uint32_t ring_count, uint32_t segment_count, lava::device_ptr device); bool load_nodes(const aiNode* node, float scale, uint32_t base_mesh, SceneNodeIndex parent_index, std::map<std::string, SceneNodeIndex>& node_indices); bool load_cameras(const aiScene* scene, float scale, const std::map<std::string, SceneNodeIndex>& node_indices); bool load_animations(const aiScene* scene, float scale, const std::map<std::string, SceneNodeIndex>& node_indices); bool load_lights(const aiScene* scene, float scale, const std::map<std::string, SceneNodeIndex>& node_indices); bool load_meshes(const aiScene* scene, float scale, uint32_t base_material, bool scene_bounds, lava::device_ptr device); - bool load_materials(const aiScene* scene, const std::string& base_name, lava::device_ptr device, lava::staging& staging); - bool load_texture(const aiMaterial* material, const std::string& base_name, aiTextureType type, lava::device_ptr device, lava::staging& staging, lava::texture::ptr& texture); + bool load_materials(const aiScene* scene, const std::string& base_name, lava::device_ptr device); + 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); void compute_scene_bounds(); void compute_mesh_bounds(SceneMesh& mesh, const glm::mat4& local_to_world); @@ -221,7 +237,7 @@ private: glm::vec3 scene_min = glm::vec3(0.0f); glm::vec3 scene_max = glm::vec3(0.0f); - const glm::vec3 ambient_color = glm::vec3(0.0f); //NOTE: Indirect should be compute using an indirect cache. + const glm::vec3 ambient_color = glm::vec3(0.0f); //NOTE: Indirect should be computed using an indirect cache. float exposure = 1.0f; bool exposure_changed = false; @@ -234,6 +250,7 @@ private: std::vector<SceneMesh> meshes; std::vector<SceneLight> lights; std::vector<SceneMaterial> materials; + std::vector<SceneTexture> textures; std::vector<SceneAnimation> animations; std::vector<lava::buffer::ptr> mesh_data_buffer; diff --git a/src/vr_application.cpp b/src/vr_application.cpp index c1e56d438310a074c508522cc6a32c69af7ef0d0..d01d36c9858ccc0cdb9bdf5811da0144a0847da8 100644 --- a/src/vr_application.cpp +++ b/src/vr_application.cpp @@ -63,6 +63,7 @@ bool VRApplication::setup(lava::name name, argh::parser cmd_line) } } + parameters.features.samplerAnisotropy = true; parameters.features.fillModeNonSolid = true; parameters.features.multiViewport = true; parameters.features.geometryShader = true; @@ -673,11 +674,17 @@ bool VRApplication::on_update(lava::delta delta_time) bool VRApplication::on_render(VkCommandBuffer command_buffer, lava::index frame) { this->frame_capture->next_frame(frame); - this->pass_timer->next_frame(command_buffer, frame, app->device); + this->pass_timer->next_frame(command_buffer, frame, this->app->device); - this->scene->write(frame); this->stereo_transform->write(frame); + if(!this->scene->stage(command_buffer, frame)) + { + lava::log()->error("Error during scene stage!"); + + return false; + } + if (!this->cache_filled) { this->shadow_cache->compute_shadow(command_buffer, frame);