Blit a region of one image into a region of another.
1146{
1149 "blit_image: source and destination must be two distinct initialised images");
1150 return false;
1151 }
1152
1155 "blit_image: formats {} to {} do not support a {} blit",
1156 vk::to_string(
src->get_format()), vk::to_string(
dst->get_format()), vk::to_string(filter));
1157 return false;
1158 }
1159
1160 const auto settled_layout = [](
const std::shared_ptr<VKImage>&
image) {
1161 const auto layout =
image->get_current_layout();
1162 const bool transient = layout == vk::ImageLayout::eUndefined
1163 || layout == vk::ImageLayout::eTransferSrcOptimal
1164 || layout == vk::ImageLayout::eTransferDstOptimal;
1165 return transient ? vk::ImageLayout::eShaderReadOnlyOptimal : layout;
1166 };
1167 const auto src_restore = settled_layout(
src);
1168 const auto dst_restore = settled_layout(
dst);
1169
1170 auto record_command = [&](vk::CommandBuffer
cmd) {
1171 const auto transition = [&
cmd](
1172 const std::shared_ptr<VKImage>&
image,
1173 vk::ImageLayout from,
1174 vk::ImageLayout to,
1175 vk::AccessFlags src_access,
1176 vk::AccessFlags dst_access,
1177 vk::PipelineStageFlags src_stage,
1178 vk::PipelineStageFlags dst_stage) {
1179 vk::ImageMemoryBarrier barrier {};
1180 barrier.oldLayout = from;
1181 barrier.newLayout = to;
1182 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1183 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1184 barrier.image =
image->get_image();
1185 barrier.subresourceRange = {
1186 image->get_aspect_flags(), 0,
1187 image->get_mip_levels(), 0,
1188 image->get_array_layers()
1189 };
1190 barrier.srcAccessMask = src_access;
1191 barrier.dstAccessMask = dst_access;
1192 cmd.pipelineBarrier(src_stage, dst_stage, vk::DependencyFlags {}, {}, {}, barrier);
1193 };
1194
1195 constexpr auto any_access = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
1196
1197 transition(
src,
src->get_current_layout(), vk::ImageLayout::eTransferSrcOptimal,
1198 any_access, vk::AccessFlagBits::eTransferRead,
1199 vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer);
1200 transition(
dst,
dst->get_current_layout(), vk::ImageLayout::eTransferDstOptimal,
1201 any_access, vk::AccessFlagBits::eTransferWrite,
1202 vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer);
1203
1205 src->get_image(), vk::ImageLayout::eTransferSrcOptimal,
1206 dst->get_image(), vk::ImageLayout::eTransferDstOptimal,
1207 1, ®ion, filter);
1208
1209 transition(
src, vk::ImageLayout::eTransferSrcOptimal, src_restore,
1210 vk::AccessFlagBits::eTransferRead, any_access,
1211 vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands);
1212 transition(
dst, vk::ImageLayout::eTransferDstOptimal, dst_restore,
1213 vk::AccessFlagBits::eTransferWrite, any_access,
1214 vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands);
1215 };
1216
1217 if (deferred) {
1219 } else {
1221 }
1222
1223 src->set_current_layout(src_restore);
1224 dst->set_current_layout(dst_restore);
1225
1226 return true;
1227}
#define MF_ERROR(comp, ctx,...)
void execute_immediate_commands(const std::function< void(vk::CommandBuffer)> &recorder)
Execute immediate command recording for buffer operations.
bool supports_blit(vk::Format src_format, vk::Format dst_format, vk::Filter filter=vk::Filter::eNearest) const
Whether a blit between two formats is supported with a filter.
void record_deferred_commands(const std::function< void(vk::CommandBuffer)> &recorder)
Record deferred command recording for buffer operations.
@ GraphicsBackend
Graphics/visual rendering backend (Vulkan, OpenGL)
@ Core
Core engine, backend, subsystems.