diff --git a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl index a94953cb599eec74fbe33dfabebef2cb3e334cb0..a75866520fe1488b03062ed4212a276336a06ba3 100644 --- a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl +++ b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_base.glsl @@ -61,7 +61,7 @@ void main() { if(parameters.layer == 1) { - float first_layer_depth = texelFetch(sampler_layer_depth, ivec2(gl_FragCoord.xy), 0).x; + float first_layer_depth = texelFetch(sampler_layer_depth, ivec2(gl_FragCoord.xy + vec2(parameters.depth_offset, 0.0)), 0).x; float first_layer_linear_depth = linear_depth(frame.projection, first_layer_depth); float current_depth = gl_FragCoord.z; @@ -85,5 +85,5 @@ void main() vec3 lighting = apply_lighting(frame.eyePosition, inPos, normal, material); outColor = vec4(lighting, 1.0); - outEncodedDepth = vec4(encode_depth(gl_FragCoord.z), 0); + outEncodedDepth = vec4(encode_depth(gl_FragCoord.z), 1.0); } diff --git a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc index 61f267acf6721df2a7d89513da4e96df871c8602..6e8df0a98c8838d264cc41e78e0bce7adf14faf7 100644 --- a/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc +++ b/res/dpr/strategy/dual_layer_reprojection/dual_layer_reprojection_parameters.inc @@ -4,6 +4,7 @@ struct DualLayerReprojectionParameters { uint layer; + float depth_offset; float constant_threshold; float slope_threshold; }; diff --git a/src/encoder/encoder.cpp b/src/encoder/encoder.cpp index 99f7d1aa3c0c27336a330f40247cb321a296534f..96a83dc2e1108fb83e86c9c08712052e1edea643 100644 --- a/src/encoder/encoder.cpp +++ b/src/encoder/encoder.cpp @@ -89,6 +89,30 @@ bool setup_device_for_encoder(EncoderType encoder_type, lava::instance& instance return false; } +bool compute_encoder_resolution(EncoderType encoder_type, EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution) +{ + switch(encoder_type) + { + case ENCODER_TYPE_VULKAN: + if (!compute_vulkan_encoder_resolution(encoder_codec, image_resolution, encoder_resolution)) + { + return false; + } + break; + case ENCODER_TYPE_NVIDIA: + if (!compute_nvidia_encoder_resolution(encoder_codec, image_resolution, encoder_resolution)) + { + return false; + } + break; + default: + lava::log()->error("Unkown encoder type!"); + return false; + } + + return true; +} + bool shutdown_encoder(EncoderType encoder_type) { switch (encoder_type) diff --git a/src/encoder/encoder.hpp b/src/encoder/encoder.hpp index 7afa7c00bac0cde6b5c9c91f3b2431e7b1b03b6a..0da903654476969b7c7e96ac04a4c9c0d3c4578d 100644 --- a/src/encoder/encoder.hpp +++ b/src/encoder/encoder.hpp @@ -128,6 +128,8 @@ public: bool setup_instance_for_encoder(EncoderType encoder_type, lava::frame_config& config); bool setup_device_for_encoder(EncoderType encoder_type, lava::instance& instance, lava::device::create_param& parameters); +bool compute_encoder_resolution(EncoderType encoder_type, EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution); + bool shutdown_encoder(EncoderType encoder_type); Encoder::Ptr make_encoder(EncoderType encoder_type); \ No newline at end of file diff --git a/src/encoder/nvidia_encoder.cpp b/src/encoder/nvidia_encoder.cpp index f75b02024c6b4ec528c8cd65522e89933fd66e86..dad440ae3efd9f78abc5c3bea86cd80662407c08 100644 --- a/src/encoder/nvidia_encoder.cpp +++ b/src/encoder/nvidia_encoder.cpp @@ -1518,6 +1518,29 @@ bool setup_device_for_nvidia_encoder(lava::instance& instance, lava::device::cre return true; } +bool compute_nvidia_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution) +{ + if (encoder_codec == ENCODER_CODEC_H264) + { + const glm::uvec2 block_size = glm::uvec2(16); //H264 macroblock size of 16x16 + encoder_resolution = glm::uvec2(glm::ceil(glm::vec2(image_resolution) / glm::vec2(block_size))) * block_size; + } + + else if (encoder_codec == ENCODER_CODEC_H265) + { + encoder_resolution = image_resolution; + } + + else + { + lava::log()->error("Nvidia Encoder: Invalid codec!"); + + return false; + } + + return true; +} + void shutdown_nvidia_encoder() { unload_library(); diff --git a/src/encoder/nvidia_encoder.hpp b/src/encoder/nvidia_encoder.hpp index ceb40737b0d68300fd794e7a923864acd3843149..44feecf9a8ee2a80b2321b5bf99187f18ef1f374 100644 --- a/src/encoder/nvidia_encoder.hpp +++ b/src/encoder/nvidia_encoder.hpp @@ -127,4 +127,6 @@ private: bool setup_instance_for_nvidia_encoder(lava::frame_config& config); bool setup_device_for_nvidia_encoder(lava::instance& instance, lava::device::create_param& parameters); +bool compute_nvidia_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution); + void shutdown_nvidia_encoder(); \ No newline at end of file diff --git a/src/encoder/vulkan_encoder.cpp b/src/encoder/vulkan_encoder.cpp index 36da40d2dc9ae8556940eca328f17c1565f8d4ba..2d271a84611c29fb94b9155a27f8ad9016c94f48 100644 --- a/src/encoder/vulkan_encoder.cpp +++ b/src/encoder/vulkan_encoder.cpp @@ -2459,6 +2459,21 @@ bool setup_device_for_vulkan_encoder(lava::instance& instance, lava::device::cre return true; } +bool compute_vulkan_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution) +{ + if (encoder_codec != ENCODER_CODEC_H264) + { + lava::log()->error("Vulkan encoder only supportes h264 encoding!"); + + return false; + } + + const glm::uvec2 block_size = glm::uvec2(16); //H264 macroblock size of 16x16 + encoder_resolution = glm::uvec2(glm::ceil(glm::vec2(image_resolution) / glm::vec2(block_size))) * block_size; + + return true; +} + void shutdown_vulkan_encoder() { diff --git a/src/encoder/vulkan_encoder.hpp b/src/encoder/vulkan_encoder.hpp index 126af55968620fb6b191a60f25c2ec5aaec5a5a7..a899b4c67ea3f02c3de9235ccefaf0dd6d8e4809 100644 --- a/src/encoder/vulkan_encoder.hpp +++ b/src/encoder/vulkan_encoder.hpp @@ -222,4 +222,6 @@ private: bool setup_instance_for_vulkan_encoder(lava::frame_config& config); bool setup_device_for_vulkan_encoder(lava::instance& instance, lava::device::create_param& parameters); +bool compute_vulkan_encoder_resolution(EncoderCodec encoder_codec, const glm::uvec2& image_resolution, glm::uvec2& encoder_resolution); + void shutdown_vulkan_encoder(); \ No newline at end of file diff --git a/src/headset/remote_headset.cpp b/src/headset/remote_headset.cpp index 88e55660eba7d65c6aaed11da6d0a2c53cd50a97..ded41085cd663959785da9c69ceed6361fbbfcb4 100644 --- a/src/headset/remote_headset.cpp +++ b/src/headset/remote_headset.cpp @@ -80,8 +80,7 @@ bool RemoteHeadset::on_create() } this->update_values(); - this->framebuffer_resolution = strategy->get_remote_framebuffer_resolution(this->display_resolution); - + if (!this->create_framebuffers()) { lava::log()->error("Remote Headset: Can't create framebuffers!"); @@ -381,9 +380,9 @@ bool RemoteHeadset::create_transport() { this->transport = make_transport(this->get_application()->get_command_parser().get_transport()); - this->transport->set_on_setup([this](const glm::u32vec2& resolution) + this->transport->set_on_setup([this](const glm::u32vec2& display_resolution) { - this->on_setup(resolution); + this->on_setup(display_resolution); }); this->transport->set_on_projection_change([this](const glm::mat4& left_eye_projection, const glm::mat4& right_eye_projection, const glm::mat4& left_head_to_eye, const glm::mat4& right_head_to_eye) { @@ -461,7 +460,11 @@ void RemoteHeadset::destroy_framebuffers() { for (lava::image::ptr& framebuffer : this->framebuffers) { - framebuffer->destroy(true); + if (framebuffer != nullptr) + { + framebuffer->destroy(true); + framebuffer = nullptr; + } } this->framebuffers.clear(); @@ -672,14 +675,26 @@ void RemoteHeadset::update_overlay() } } -void RemoteHeadset::on_setup(const glm::u32vec2& resolution) +void RemoteHeadset::on_setup(const glm::u32vec2& display_resolution) { - EncoderCodec codec = this->get_application()->get_command_parser().get_codec(); + StereoStrategy::Ptr strategy = this->get_application()->get_stereo_strategy(); + glm::uvec2 framebuffer_resolution = strategy->get_remote_framebuffer_resolution(display_resolution); + + EncoderType encoder_type = this->get_application()->get_command_parser().get_encoder(); + EncoderCodec encoder_codec = this->get_application()->get_command_parser().get_codec(); + glm::uvec2 encode_resolution = glm::uvec2(0); + + if (!compute_encoder_resolution(encoder_type, encoder_codec, framebuffer_resolution, encode_resolution)) + { + return; + } - this->transport->send_setup_complete(this->remote_strategy, codec, this->frame_id_count, this->near_plane, this->far_plane); + this->transport->send_setup_complete(this->remote_strategy, this->frame_id_count, encoder_codec, encode_resolution, framebuffer_resolution, this->near_plane, this->far_plane); std::unique_lock<std::mutex> lock(this->transport_mutex); - this->display_resolution = resolution; + this->display_resolution = display_resolution; + this->framebuffer_resolution = framebuffer_resolution; + this->encode_resolution = encode_resolution; lock.unlock(); } diff --git a/src/headset/remote_headset.hpp b/src/headset/remote_headset.hpp index 4a68edf7b606c203b5177799f5baa5fbd9ba971b..165e26c60c9c07f6183ccd0b81997ecaf3a9dc3d 100644 --- a/src/headset/remote_headset.hpp +++ b/src/headset/remote_headset.hpp @@ -62,7 +62,7 @@ private: void update_stage(lava::delta delta_time); void update_overlay(); - void on_setup(const glm::u32vec2& resolution); + void on_setup(const glm::u32vec2& display_resolution); void on_projection_change(const glm::mat4& left_eye_projection, const glm::mat4& right_eye_projection, const glm::mat4& left_head_to_eye, const glm::mat4& right_head_to_eye); void on_head_transform(TransformId transform_id, const glm::mat4& head_transform); void on_controller_transform(Controller controller, const glm::mat4& controller_transform); @@ -109,10 +109,11 @@ private: uint32_t frame_id_count = 0; uint32_t transform_id = 0; //NOTE: Protected by transport_mutex - glm::uvec2 framebuffer_resolution; + glm::uvec2 framebuffer_resolution; //NOTE: Protected by transport_mutex, but accessable after setup lava::image::ptr framebuffer_array; std::vector<lava::image::ptr> framebuffers; + glm::uvec2 encode_resolution; //NOTE: Protected by transport_mutex, but accessable after setup std::vector<Encoder::Ptr> encoders; std::vector<std::fstream> encoder_files; uint32_t encoder_mode = ENCODER_MODE_CONSTANT_BITRATE; diff --git a/src/strategy/dual_layer_reprojection.cpp b/src/strategy/dual_layer_reprojection.cpp index 5ca05a10e083cb3977122d3de36a7b0e4693d8c5..c6a13f9299e852e3bcd2bf6dfabe0d7fbbcc6d0d 100644 --- a/src/strategy/dual_layer_reprojection.cpp +++ b/src/strategy/dual_layer_reprojection.cpp @@ -93,14 +93,20 @@ void DualLayerReprojection::on_destroy() for (uint32_t index = 0; index < this->layer_depth_buffers.size(); index++) { - this->layer_depth_buffers[index]->destroy(); - this->layer_depth_buffers[index] = nullptr; + if (this->layer_depth_buffers[index] != nullptr) + { + this->layer_depth_buffers[index]->destroy(); + this->layer_depth_buffers[index] = nullptr; + } } - if (this->encoded_depth_buffer != nullptr) + for (uint32_t index = 0; index < this->encoded_depth_buffers.size(); index++) { - this->encoded_depth_buffer->destroy(); - this->encoded_depth_buffer = nullptr; + if (this->encoded_depth_buffers[index] != nullptr) + { + this->encoded_depth_buffers[index]->destroy(); + this->encoded_depth_buffers[index] = nullptr; + } } } @@ -146,71 +152,65 @@ bool DualLayerReprojection::on_render(VkCommandBuffer command_buffer, lava::inde if (this->setup_layout) { - VkImageMemoryBarrier image_barrier; - image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_barrier.pNext = nullptr; - image_barrier.srcAccessMask = 0; - image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barrier.image = this->layer_depth_buffers[1]->get(); - image_barrier.subresourceRange = this->layer_depth_buffers[1]->get_subresource_range(); + VkImageMemoryBarrier depth_barrier; + depth_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + depth_barrier.pNext = nullptr; + depth_barrier.srcAccessMask = 0; + depth_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + depth_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depth_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + depth_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + depth_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + depth_barrier.image = this->layer_depth_buffers[1]->get(); + depth_barrier.subresourceRange = this->layer_depth_buffers[1]->get_subresource_range(); + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &depth_barrier); + + if (!this->get_headset()->is_remote()) + { + std::array<VkImageMemoryBarrier, 2> encoded_depth_barriers; + + for (uint32_t index = 0; index < encoded_depth_barriers.size(); index++) + { + VkImageMemoryBarrier& encoded_depth_barrier = encoded_depth_barriers[index]; + encoded_depth_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + encoded_depth_barrier.pNext = nullptr; + encoded_depth_barrier.srcAccessMask = 0; + encoded_depth_barrier.dstAccessMask = 0; + encoded_depth_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + encoded_depth_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + encoded_depth_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + encoded_depth_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + encoded_depth_barrier.image = this->encoded_depth_buffers[index]->get(); + encoded_depth_barrier.subresourceRange = this->encoded_depth_buffers[index]->get_subresource_range(); + } + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, encoded_depth_barriers.size(), encoded_depth_barriers.data()); + } - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_barrier); this->setup_layout = false; } + VkImageMemoryBarrier framebuffer_barrier; + framebuffer_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + framebuffer_barrier.pNext = nullptr; + framebuffer_barrier.srcAccessMask = 0; + framebuffer_barrier.dstAccessMask = 0; + framebuffer_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + framebuffer_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + framebuffer_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + framebuffer_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + framebuffer_barrier.image = this->get_headset()->get_framebuffer_array()->get(); + framebuffer_barrier.subresourceRange = this->get_headset()->get_framebuffer_array()->get_subresource_range(); + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &framebuffer_barrier); + this->get_pass_timer()->begin_pass(command_buffer, "first_layer"); this->layer = 0; this->layer_pass->process(command_buffer, 0); this->get_pass_timer()->end_pass(command_buffer); - if (this->get_headset()->is_remote()) - { - this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color"); - this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth"); - - switch (this->overlay) - { - case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR: - this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - break; - case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH: - this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - break; - default: - lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!"); - return false; - } - - this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); - this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); - } - - else - { - this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color"); - this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth"); - - switch (this->overlay) - { - case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR: - this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - break; - case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH: - this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - break; - default: - lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!"); - return false; - } - - this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, EYE_LEFT); - } - this->get_pass_timer()->begin_pass(command_buffer, "second_layer"); this->layer = 1; this->layer_pass->process(command_buffer, 1); @@ -218,44 +218,59 @@ bool DualLayerReprojection::on_render(VkCommandBuffer command_buffer, lava::inde if (this->get_headset()->is_remote()) { - this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(2), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_color"); - this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(3), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth"); + glm::uvec2 display_resolution = this->get_headset()->get_display_resolution(); + glm::uvec2 layer_offset1 = glm::uvec2(0); + glm::uvec2 layer_offset2 = glm::uvec2(display_resolution.x, 0); + + this->get_frame_capture()->capture_image(command_buffer, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color"); + this->get_frame_capture()->capture_image(command_buffer, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_color"); + + this->get_frame_capture()->capture_image(command_buffer, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth"); + this->get_frame_capture()->capture_image(command_buffer, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth"); switch (this->overlay) { case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR: - this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->get_headset()->get_framebuffer(2), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(0), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); break; case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH: - this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->get_headset()->get_framebuffer(3), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, layer_offset1, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, layer_offset2, display_resolution, this->get_headset()->get_framebuffer(1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); break; default: lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!"); return false; } - this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 2); - this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3); + this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0); + this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); } else { + this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_color"); this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_RIGHT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_color"); - this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth"); + + this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffers[0], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "first_layer_encoded_depth"); + this->get_frame_capture()->capture_image(command_buffer, this->encoded_depth_buffers[1], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "second_layer_encoded_depth"); switch (this->overlay) { case DUAL_LAYER_REPROJECTION_OVERLAY_COLOR: + this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->get_headset()->get_framebuffer(EYE_RIGHT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); break; case DUAL_LAYER_REPROJECTION_OVERLAY_ENCODED_DEPTH: - this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->encoded_depth_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + this->get_companion_window()->submit_image(command_buffer, EYE_LEFT, this->encoded_depth_buffers[0], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + this->get_companion_window()->submit_image(command_buffer, EYE_RIGHT, this->encoded_depth_buffers[1], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); break; default: lava::log()->error("Dual Layer Reprojection: Invalid overlay mode!"); return false; } + this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, EYE_LEFT); this->get_headset()->submit_frame(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, EYE_RIGHT); } @@ -284,7 +299,7 @@ bool DualLayerReprojection::create_buffers() lava::image::ptr depth_buffer = lava::make_image(VK_FORMAT_D32_SFLOAT); depth_buffer->set_usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - if (!depth_buffer->create(this->get_device(), this->get_headset()->get_resolution())) + if (!depth_buffer->create(this->get_device(), this->get_headset()->get_framebuffer_resolution())) { lava::log()->error("Dual Layer Reprojection: Can't create layer depth buffer!"); @@ -296,14 +311,19 @@ bool DualLayerReprojection::create_buffers() if (!this->get_headset()->is_remote()) { - this->encoded_depth_buffer = lava::make_image(VK_FORMAT_R8G8B8A8_UNORM); - this->encoded_depth_buffer->set_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT| VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - - if (!this->encoded_depth_buffer->create(this->get_device(), this->get_headset()->get_resolution())) + for (uint32_t index = 0; index < this->encoded_depth_buffers.size(); index++) { - lava::log()->error("Dual Layer Reprojection: Can't create encoded depth buffer!"); + lava::image::ptr encoded_depth_buffer = lava::make_image(VK_FORMAT_R8G8B8A8_UNORM); + encoded_depth_buffer->set_usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - return false; + if (!encoded_depth_buffer->create(this->get_device(), this->get_headset()->get_framebuffer_resolution())) + { + lava::log()->error("Dual Layer Reprojection: Can't create encoded depth buffer!"); + + return false; + } + + this->encoded_depth_buffers[index] = encoded_depth_buffer; } } @@ -406,14 +426,21 @@ bool DualLayerReprojection::create_layer_pass() depth_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); lava::attachment::ptr color_attachment = lava::make_attachment(this->get_headset()->get_format()); - color_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); + color_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); color_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - color_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + color_attachment->set_layouts(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + VkFormat encoded_depth_format = VK_FORMAT_R8G8B8A8_UNORM; + + if (this->get_headset()->is_remote()) + { + encoded_depth_format = this->get_headset()->get_format(); + } - lava::attachment::ptr encoded_depth_attachment = lava::make_attachment(VK_FORMAT_R8G8B8A8_UNORM); - encoded_depth_attachment->set_op(VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE); + lava::attachment::ptr encoded_depth_attachment = lava::make_attachment(encoded_depth_format); + encoded_depth_attachment->set_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE); encoded_depth_attachment->set_stencil_op(VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); - encoded_depth_attachment->set_layouts(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + encoded_depth_attachment->set_layouts(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VkAttachmentReference color_attachment_reference; color_attachment_reference.attachment = 1; @@ -427,18 +454,6 @@ bool DualLayerReprojection::create_layer_pass() depth_clear_value.depthStencil.depth = 1.0f; depth_clear_value.depthStencil.stencil = 0; - VkClearValue color_clear_value; - color_clear_value.color.float32[0] = 0.0f; - color_clear_value.color.float32[1] = 0.0f; - color_clear_value.color.float32[2] = 0.0f; - color_clear_value.color.float32[3] = 1.0f; - - VkClearValue encoded_depth_clear_value; - encoded_depth_clear_value.color.float32[0] = 0.0f; - encoded_depth_clear_value.color.float32[1] = 0.0f; - encoded_depth_clear_value.color.float32[2] = 0.0f; - encoded_depth_clear_value.color.float32[3] = 1.0f; - lava::subpass::ptr subpass = lava::make_subpass(); subpass->set_depth_stencil_attachment(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); subpass->set_color_attachments( @@ -465,15 +480,13 @@ bool DualLayerReprojection::create_layer_pass() this->layer_pass->set_clear_values( { depth_clear_value, - color_clear_value, - encoded_depth_clear_value }); lava::VkAttachments framebuffer_views; lava::rect framebuffer_area = { glm::vec2(0.0f), - this->get_headset()->get_resolution() + this->get_headset()->get_framebuffer_resolution() }; if (this->get_headset()->is_remote()) @@ -481,7 +494,7 @@ bool DualLayerReprojection::create_layer_pass() framebuffer_views = { { this->layer_depth_buffers[0]->get_view(), this->get_headset()->get_framebuffer(0)->get_view(), this->get_headset()->get_framebuffer(1)->get_view() }, - { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(2)->get_view(), this->get_headset()->get_framebuffer(3)->get_view() } + { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(0)->get_view(), this->get_headset()->get_framebuffer(1)->get_view() }, }; } @@ -489,8 +502,8 @@ bool DualLayerReprojection::create_layer_pass() { framebuffer_views = { - { this->layer_depth_buffers[0]->get_view(), this->get_headset()->get_framebuffer(EYE_LEFT)->get_view(), this->encoded_depth_buffer->get_view() }, - { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(EYE_RIGHT)->get_view(), this->encoded_depth_buffer->get_view() } + { this->layer_depth_buffers[0]->get_view(), this->get_headset()->get_framebuffer(EYE_LEFT)->get_view(), this->encoded_depth_buffers[0]->get_view() }, + { this->layer_depth_buffers[1]->get_view(), this->get_headset()->get_framebuffer(EYE_RIGHT)->get_view(), this->encoded_depth_buffers[1]->get_view() } }; } @@ -611,13 +624,47 @@ void DualLayerReprojection::process_layer_pass(VkCommandBuffer command_buffer) uint32_t frame_index = this->get_application()->get_frame_index(); uint32_t read_index = (this->layer + 1) % 2; + if (this->layer == 0) + { + std::array<VkClearAttachment, 2> clear_attachments; + clear_attachments[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clear_attachments[0].colorAttachment ///TODO: ......... + + + vkCmdClearAttachments(command_buffer, 2, ) + } + glsl::DualLayerReprojectionParameters parameters; parameters.layer = this->layer; + parameters.depth_offset = 0.0f; parameters.constant_threshold = this->layer_constant_threshold; parameters.slope_threshold = this->layer_slope_threshold; + if (this->get_headset()->is_remote() && this->layer == 1) + { + parameters.depth_offset = -this->get_headset()->get_display_resolution().x; + } + vkCmdPushConstants(command_buffer, this->layer_pipeline_layout->get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(parameters), ¶meters); + if (this->get_headset()->is_remote()) + { + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = this->get_headset()->get_display_resolution().x; + viewport.height = this->get_headset()->get_display_resolution().y; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + if (this->layer == 1) + { + viewport.x = this->get_headset()->get_display_resolution().x; + } + + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + } + this->layer_pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(EYE_LEFT, frame_index), 0); this->layer_pipeline_layout->bind(command_buffer, this->get_scene()->get_light_descriptor_set(frame_index), 3); this->layer_pipeline_layout->bind(command_buffer, this->layer_descriptor_sets[read_index], 4); diff --git a/src/strategy/dual_layer_reprojection.hpp b/src/strategy/dual_layer_reprojection.hpp index 79d71c4a350772b51f0cec63c80e6d70ac7f8e75..de959f2b97eea4c273f48db8ee78a50c38e44e03 100644 --- a/src/strategy/dual_layer_reprojection.hpp +++ b/src/strategy/dual_layer_reprojection.hpp @@ -53,7 +53,7 @@ private: float reproject_slope_threshold = 0.1f; std::array<lava::image::ptr, 2> layer_depth_buffers; - lava::image::ptr encoded_depth_buffer; + std::array<lava::image::ptr, 2> encoded_depth_buffers; lava::descriptor::pool::ptr descriptor_pool; lava::descriptor::ptr layer_descriptor; diff --git a/src/transport/transport.hpp b/src/transport/transport.hpp index cafde57896524ad5659d7031cec5e3e6e9155b56..a0ec28b17938d726f7f326494f5f5c85616443eb 100644 --- a/src/transport/transport.hpp +++ b/src/transport/transport.hpp @@ -53,8 +53,8 @@ public: typedef std::shared_ptr<Transport> Ptr; // OnSetup: Used during the initial handshake - // resolution: The resolution that should be used for rendering - typedef std::function<void(const glm::u32vec2& resolution)> OnSetup; + // display_resolution: The resolution of the headset displays + typedef std::function<void(const glm::u32vec2& display_resolution)> OnSetup; // OnProjectionChange: Used to change the projection matrices. Needs to be send once after the handshake. // left_eye_projection: The projection matrix that should be used for the left eye @@ -112,12 +112,14 @@ public: // send_setup_complete: Used to send a setup-complete packet // This function should be threadsafe and callable by main and worker thread - // remote_strategy: The postprocessing method that should be used on the headset - // codec: The codec that is used for the encoding of the images. - // max_frame_ids: The number of images that define a frame and that are send in parallel (normaly 2 for left and right eye). The headset application should setup this many decoders - // near_plane: The distance to the near plane that should be used for the projection matrices - // far_plane: The distance to the far plane that should be used for the projection matrices - virtual bool send_setup_complete(RemoteStrategy remote_strategy, EncoderCodec codec, uint32_t max_frame_ids, float near_plane, float far_plane) = 0; + // remote_strategy: The postprocessing method that should be used on the headset + // max_frame_ids: The number of images that define a frame and that are send in parallel (normaly 2 for left and right eye). The headset application should setup this many decoders + // codec: The codec that is used for the encoding of the images. + // encode_resolution: The resolution that is used by the encoder and decoder. The resolution could be bigger than the display resolution due to alignments + // render_resoluion: The resolution used by the host during rendering + // near_plane: The distance to the near plane that should be used for the projection matrices + // far_plane: The distance to the far plane that should be used for the projection matrices + virtual bool send_setup_complete(RemoteStrategy remote_strategy, uint32_t max_frame_ids, EncoderCodec codec, const glm::uvec2& encode_resolution, const glm::uvec2& render_resolution, float near_plane, float far_plane) = 0; // send_stage_transform: Used to send the current transformation for the origin // This transformation can change for example if the user moves by pressing a controller button diff --git a/src/transport/udp_packet.hpp b/src/transport/udp_packet.hpp index 7b1afa2cc4fd4b421c383db8d8838895eb916ddc..9aa58ecea2192358647e913d2b5f5df8bb809c3a 100644 --- a/src/transport/udp_packet.hpp +++ b/src/transport/udp_packet.hpp @@ -133,7 +133,7 @@ struct UDPPacketSetup UDPPacketId id = UDP_PACKET_ID_SETUP; uint32_t size = 0; - glm::u32vec2 resolution; + glm::u32vec2 display_resolution; }; struct UDPPacketSetupComplete @@ -142,9 +142,12 @@ struct UDPPacketSetupComplete uint32_t size = 0; UDPStereoStrategyId strategy_id; - UDPCodec codec; uint32_t max_frame_ids; + UDPCodec codec; + glm::uvec2 encode_resolution; + glm::uvec2 render_resolution; + float near_plane; float far_plane; }; diff --git a/src/transport/udp_transport.cpp b/src/transport/udp_transport.cpp index 9ef30b3e3f8bfadc82cc325143d7636072fcb3ce..b07872b458cf12258f444a32d1794e209f3deae4 100644 --- a/src/transport/udp_transport.cpp +++ b/src/transport/udp_transport.cpp @@ -98,7 +98,7 @@ bool UDPTransport::wait_connect() return this->get_state() == TRANSPORT_STATE_CONNECTED; } -bool UDPTransport::send_setup_complete(RemoteStrategy remote_strategy, EncoderCodec codec, uint32_t max_frame_ids, float near_plane, float far_plane) +bool UDPTransport::send_setup_complete(RemoteStrategy remote_strategy, uint32_t max_frame_ids, EncoderCodec codec, const glm::uvec2& encode_resolution, const glm::uvec2& render_resolution, float near_plane, float far_plane) { if (this->get_state() != TRANSPORT_STATE_CONNECTED) { @@ -129,8 +129,10 @@ bool UDPTransport::send_setup_complete(RemoteStrategy remote_strategy, EncoderCo packet->id = UDP_PACKET_ID_SETUP_COMPLETE; packet->size = sizeof(UDPPacketSetupComplete); packet->strategy_id = udp_strategy; - packet->codec = udp_codec; packet->max_frame_ids = max_frame_ids; + packet->codec = udp_codec; + packet->encode_resolution = encode_resolution; + packet->render_resolution = render_resolution; packet->near_plane = near_plane; packet->far_plane = far_plane; @@ -814,7 +816,7 @@ void UDPTransport::parse_setup(const Datagram& datagram) return; } - this->on_setup(packet->resolution); + this->on_setup(packet->display_resolution); } void UDPTransport::parse_projection_change(const Datagram& datagram) diff --git a/src/transport/udp_transport.hpp b/src/transport/udp_transport.hpp index 909918cd8e8fff774e45696edbb4d7499e969c1d..173cdd6c73274dd3b09495ec238c1bd37d8f5944 100644 --- a/src/transport/udp_transport.hpp +++ b/src/transport/udp_transport.hpp @@ -23,7 +23,7 @@ public: void destroy() override; bool wait_connect() override; - bool send_setup_complete(RemoteStrategy remote_strategy, EncoderCodec codec, uint32_t max_frame_ids, float near_plane, float far_plane) override; + bool send_setup_complete(RemoteStrategy remote_strategy, uint32_t max_frame_ids, EncoderCodec codec, const glm::uvec2& encode_resolution, const glm::uvec2& render_resolution, float near_plane, float far_plane) override; bool send_stage_transform(const glm::mat4& stage_transform) override; bool send_frame_config_nal(FrameId frame_id, const std::span<const uint8_t>& content) override; bool send_frame_nal(FrameNumber frame_number, FrameId frame_id, TransformId transform_id, const std::span<const uint8_t>& content) override; diff --git a/src/utility/companion_window.cpp b/src/utility/companion_window.cpp index 078a674517246c398ed988f821d7e381927293cd..8d70778c911cac3a1335be43652459044a416087 100644 --- a/src/utility/companion_window.cpp +++ b/src/utility/companion_window.cpp @@ -90,6 +90,11 @@ void CompanionWindow::render(VkCommandBuffer command_buffer, lava::render_target } void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, lava::image::ptr image, VkImageLayout image_layout) +{ + this->submit_image(command_buffer, eye, glm::uvec2(0), image->get_size(), image, image_layout); +} + +void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, const glm::uvec2& submit_offset, const glm::uvec2& submit_size, lava::image::ptr image, VkImageLayout image_layout) { if (!this->enabled) { @@ -137,7 +142,6 @@ void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, lava subresource_layers.layerCount = 1; glm::uvec2 buffer_resolution = this->framebuffer->get_size(); - glm::uvec2 image_resolution = image->get_size(); uint32_t eye_offset = 0; if (eye == EYE_RIGHT) @@ -147,11 +151,11 @@ void CompanionWindow::submit_image(VkCommandBuffer command_buffer, Eye eye, lava VkImageBlit image_blit; image_blit.srcSubresource = image->get_subresource_layers(); - image_blit.srcOffsets[0].x = 0; - image_blit.srcOffsets[0].y = 0; + image_blit.srcOffsets[0].x = submit_offset.x; + image_blit.srcOffsets[0].y = submit_offset.y; image_blit.srcOffsets[0].z = 0; - image_blit.srcOffsets[1].x = image_resolution.x; - image_blit.srcOffsets[1].y = image_resolution.y; + image_blit.srcOffsets[1].x = submit_offset.x + submit_size.x; + image_blit.srcOffsets[1].y = submit_offset.y + submit_size.y; image_blit.srcOffsets[1].z = 1; image_blit.dstSubresource = subresource_layers; image_blit.dstOffsets[0].x = eye_offset; diff --git a/src/utility/companion_window.hpp b/src/utility/companion_window.hpp index f4b814c362a9777ae74129720c253ccd2aa55db8..4c3445dd3fc0a8705a8782b4d5e497071bfd157b 100644 --- a/src/utility/companion_window.hpp +++ b/src/utility/companion_window.hpp @@ -30,6 +30,7 @@ public: // The image format of the given image needs to be a four channel color type where each channel has a bit-depth of one byte. // After the image is copied to the companion window, its image layout is restored. void submit_image(VkCommandBuffer command_buffer, Eye eye, lava::image::ptr image, VkImageLayout image_layout); + void submit_image(VkCommandBuffer command_buffer, Eye eye, const glm::uvec2& submit_offset, const glm::uvec2& submit_size, lava::image::ptr image, VkImageLayout image_layout); void set_enabled(bool enabled); bool is_enabled() const; diff --git a/src/utility/frame_capture.cpp b/src/utility/frame_capture.cpp index 5c8680b53d5229de33baf8bb6c51bb8c69468748..4ff9bc5a87d7a87829b4342b7dd2a796392c0e51 100644 --- a/src/utility/frame_capture.cpp +++ b/src/utility/frame_capture.cpp @@ -35,6 +35,11 @@ void FrameCapture::next_frame(lava::index frame) } void FrameCapture::capture_image(VkCommandBuffer command_buffer, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name) +{ + this->capture_image(command_buffer, glm::uvec2(0), image->get_size(), image, image_layout, image_name); +} + +void FrameCapture::capture_image(VkCommandBuffer command_buffer, const glm::uvec2& capture_offset, const glm::uvec2& capture_size, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name) { if (!this->enabled) { @@ -42,22 +47,21 @@ void FrameCapture::capture_image(VkCommandBuffer command_buffer, lava::image::pt } lava::device_ptr device = image->get_device(); - lava::uv2 image_size = image->get_size(); VkFormat image_format = image->get_format(); - uint32_t staging_buffer_size = image_size.x * image_size.y * this->get_component_count(image_format) * this->get_component_size(image_format); + uint32_t staging_buffer_size = capture_size.x * capture_size.y * this->get_component_count(image_format) * this->get_component_size(image_format); lava::buffer::ptr staging_buffer = lava::make_buffer(); staging_buffer->create(device, nullptr, staging_buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, false, VmaMemoryUsage::VMA_MEMORY_USAGE_GPU_TO_CPU); VkOffset3D image_offset; - image_offset.x = 0; - image_offset.y = 0; + image_offset.x = capture_offset.x; + image_offset.y = capture_offset.y; image_offset.z = 0; VkExtent3D image_extend; - image_extend.width = image_size.x; - image_extend.height = image_size.y; + image_extend.width = capture_size.x; + image_extend.height = capture_size.y; image_extend.depth = 1; VkImageMemoryBarrier begin_barrier; @@ -129,7 +133,7 @@ void FrameCapture::capture_image(VkCommandBuffer command_buffer, lava::image::pt ImageCapture capture; capture.frame_index = this->current_frame; capture.name = image_name; - capture.size = image_size; + capture.size = capture_size; capture.format = image_format; capture.store_directory = directory.name; capture.store_index = directory.index; diff --git a/src/utility/frame_capture.hpp b/src/utility/frame_capture.hpp index 4a4a86b61997fd2424d33c7695c2ad252bee49fe..781291a41085d4f9132aecd18f5b34d46ce4def6 100644 --- a/src/utility/frame_capture.hpp +++ b/src/utility/frame_capture.hpp @@ -53,6 +53,7 @@ public: void next_frame(lava::index frame); void capture_image(VkCommandBuffer command_buffer, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name); + void capture_image(VkCommandBuffer command_buffer, const glm::uvec2& capture_offset, const glm::uvec2& capture_size, lava::image::ptr image, VkImageLayout image_layout, const std::string& image_name); void set_enabled(bool enabled); bool is_enabled() const;