From: Mikko Rasa Date: Wed, 1 Dec 2021 08:31:43 +0000 (+0200) Subject: Implement mipmap generation for the Vulkan backend X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=d2a23243b7f25e56ef098196b2962c103989143f;p=libs%2Fgl.git Implement mipmap generation for the Vulkan backend --- diff --git a/source/backends/vulkan/texture1d_backend.cpp b/source/backends/vulkan/texture1d_backend.cpp index e28ec423..d66732bf 100644 --- a/source/backends/vulkan/texture1d_backend.cpp +++ b/source/backends/vulkan/texture1d_backend.cpp @@ -53,6 +53,23 @@ void VulkanTexture1D::sub_image(unsigned level, int x, unsigned wd, const void * copy(src, src+data_size, static_cast(staging)); } +void VulkanTexture1D::generate_mipmap() +{ + generate_mipmap_levels(static_cast(this)->levels); +} + +void VulkanTexture1D::fill_mipmap_blit(unsigned level, void *b) +{ + const Texture1D &self = *static_cast(this); + VkImageBlit &blit = *static_cast(b); + + int src_size = self.get_level_size(level); + int dst_size = self.get_level_size(level+1); + + blit.srcOffsets[1] = { src_size, 1, 1 }; + blit.dstOffsets[1] = { dst_size, 1, 1 }; +} + size_t VulkanTexture1D::get_data_size() const { return 0; diff --git a/source/backends/vulkan/texture1d_backend.h b/source/backends/vulkan/texture1d_backend.h index 424d262a..675da1b2 100644 --- a/source/backends/vulkan/texture1d_backend.h +++ b/source/backends/vulkan/texture1d_backend.h @@ -13,6 +13,8 @@ protected: virtual void fill_image_info(void *) const; void sub_image(unsigned, int, unsigned, const void *); + virtual void generate_mipmap(); + virtual void fill_mipmap_blit(unsigned, void *); public: virtual AsyncLoader *load(IO::Seekable &, const Resources * = 0) { return 0; } diff --git a/source/backends/vulkan/texture2d_backend.cpp b/source/backends/vulkan/texture2d_backend.cpp index 71fb90cd..518f4c2e 100644 --- a/source/backends/vulkan/texture2d_backend.cpp +++ b/source/backends/vulkan/texture2d_backend.cpp @@ -54,6 +54,23 @@ void VulkanTexture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsig copy(src, src+data_size, static_cast(staging)); } +void VulkanTexture2D::generate_mipmap() +{ + generate_mipmap_levels(static_cast(this)->levels); +} + +void VulkanTexture2D::fill_mipmap_blit(unsigned level, void *b) +{ + const Texture2D &self = *static_cast(this); + VkImageBlit &blit = *static_cast(b); + + auto src_size = self.get_level_size(level); + auto dst_size = self.get_level_size(level+1); + + blit.srcOffsets[1] = { static_cast(src_size.x), static_cast(src_size.y), 1 }; + blit.dstOffsets[1] = { static_cast(dst_size.x), static_cast(dst_size.y), 1 }; +} + Resource::AsyncLoader *VulkanTexture2D::load(IO::Seekable &, const Resources *) { throw logic_error("Texture2D::load is unimplemented"); diff --git a/source/backends/vulkan/texture2d_backend.h b/source/backends/vulkan/texture2d_backend.h index 1a5377ed..cfd5ff3d 100644 --- a/source/backends/vulkan/texture2d_backend.h +++ b/source/backends/vulkan/texture2d_backend.h @@ -13,6 +13,8 @@ protected: virtual void fill_image_info(void *) const; void sub_image(unsigned, int, int, unsigned, unsigned, const void *); + virtual void generate_mipmap(); + virtual void fill_mipmap_blit(unsigned, void *); public: virtual Resource::AsyncLoader *load(IO::Seekable &, const Resources * = 0); diff --git a/source/backends/vulkan/texture2dmultisample_backend.cpp b/source/backends/vulkan/texture2dmultisample_backend.cpp index 4a81273b..2e39c653 100644 --- a/source/backends/vulkan/texture2dmultisample_backend.cpp +++ b/source/backends/vulkan/texture2dmultisample_backend.cpp @@ -1,3 +1,4 @@ +#include "error.h" #include "frameformat.h" #include "texture2dmultisample.h" #include "texture2dmultisample_backend.h" @@ -23,6 +24,11 @@ void VulkanTexture2DMultisample::fill_image_info(void *ii) const image_info->samples = static_cast(get_vulkan_samples(self.samples)); } +void VulkanTexture2DMultisample::generate_mipmap() +{ + throw invalid_operation("VulkanTexture2DMultisample::generate_mipmap"); +} + size_t VulkanTexture2DMultisample::get_data_size() const { return 0; diff --git a/source/backends/vulkan/texture2dmultisample_backend.h b/source/backends/vulkan/texture2dmultisample_backend.h index d20e33bc..392fb0fb 100644 --- a/source/backends/vulkan/texture2dmultisample_backend.h +++ b/source/backends/vulkan/texture2dmultisample_backend.h @@ -12,6 +12,8 @@ protected: VulkanTexture2DMultisample(); virtual void fill_image_info(void *) const; + virtual void generate_mipmap(); + virtual void fill_mipmap_blit(unsigned, void *) { } public: virtual AsyncLoader *load(IO::Seekable &, const Resources * = 0) { return 0; } diff --git a/source/backends/vulkan/texture3d_backend.cpp b/source/backends/vulkan/texture3d_backend.cpp index 581206c6..44a25904 100644 --- a/source/backends/vulkan/texture3d_backend.cpp +++ b/source/backends/vulkan/texture3d_backend.cpp @@ -59,6 +59,25 @@ void VulkanTexture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd copy(src, src+data_size, static_cast(staging)); } +void VulkanTexture3D::generate_mipmap() +{ + generate_mipmap_levels(static_cast(this)->levels); +} + +void VulkanTexture3D::fill_mipmap_blit(unsigned level, void *b) +{ + const Texture3D &self = *static_cast(this); + VkImageBlit &blit = *static_cast(b); + + LinAl::Vector src_size = self.get_level_size(level); + LinAl::Vector dst_size = self.get_level_size(level+1); + + blit.srcSubresource.layerCount = (is_array() ? self.depth : 1); + blit.dstSubresource.layerCount = blit.srcSubresource.layerCount; + blit.srcOffsets[1] = { src_size.x, src_size.y, (is_array() ? 1 : src_size.z) }; + blit.dstOffsets[1] = { dst_size.x, dst_size.y, (is_array() ? 1 : dst_size.z) }; +} + bool VulkanTexture3D::is_array() const { return view_type==VK_IMAGE_VIEW_TYPE_2D_ARRAY; diff --git a/source/backends/vulkan/texture3d_backend.h b/source/backends/vulkan/texture3d_backend.h index c5bdeb57..e1c8f8f5 100644 --- a/source/backends/vulkan/texture3d_backend.h +++ b/source/backends/vulkan/texture3d_backend.h @@ -14,6 +14,8 @@ protected: virtual void fill_image_info(void *) const; void sub_image(unsigned, int, int, int, unsigned, unsigned, unsigned, const void *); + virtual void generate_mipmap(); + virtual void fill_mipmap_blit(unsigned, void *); bool is_array() const; diff --git a/source/backends/vulkan/texture_backend.cpp b/source/backends/vulkan/texture_backend.cpp index f1e8b85b..168d6adb 100644 --- a/source/backends/vulkan/texture_backend.cpp +++ b/source/backends/vulkan/texture_backend.cpp @@ -56,7 +56,7 @@ void VulkanTexture::allocate() image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - image_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT; PixelComponents comp = get_components(self.storage_fmt); if(comp==DEPTH_COMPONENT || comp==STENCIL_INDEX) image_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; @@ -100,9 +100,33 @@ void VulkanTexture::allocate() set_vulkan_object_names(); } -void VulkanTexture::generate_mipmap() +void VulkanTexture::generate_mipmap_levels(unsigned n_levels) { - throw logic_error("VulkanTexture::generate_mipmap is unimplemented"); + TransferQueue &tq = device.get_transfer_queue(); + for(unsigned i=0; i+1(this)->storage_fmt)); + region.srcSubresource.mipLevel = i; + region.srcSubresource.baseArrayLayer = 0; + region.srcSubresource.layerCount = 1; + region.dstSubresource = region.srcSubresource; + ++region.dstSubresource.mipLevel; + + fill_mipmap_blit(i, ®ion); + + vk.CmdBlitImage(cmd_buf, handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion, VK_FILTER_LINEAR); + }); + } } void VulkanTexture::change_layout(unsigned n_levels, int level, unsigned layout, bool discard) const diff --git a/source/backends/vulkan/texture_backend.h b/source/backends/vulkan/texture_backend.h index 123c6e4b..9d043500 100644 --- a/source/backends/vulkan/texture_backend.h +++ b/source/backends/vulkan/texture_backend.h @@ -30,7 +30,9 @@ protected: virtual void fill_image_info(void *) const = 0; void require_swizzle() { } - void generate_mipmap(); + virtual void generate_mipmap() = 0; + void generate_mipmap_levels(unsigned); + virtual void fill_mipmap_blit(unsigned, void *) = 0; void change_layout(unsigned, int, unsigned, bool) const; diff --git a/source/backends/vulkan/texturecube_backend.cpp b/source/backends/vulkan/texturecube_backend.cpp index 5b7bd368..98f00044 100644 --- a/source/backends/vulkan/texturecube_backend.cpp +++ b/source/backends/vulkan/texturecube_backend.cpp @@ -56,6 +56,25 @@ void VulkanTextureCube::sub_image(unsigned face, unsigned level, int x, int y, u copy(src, src+data_size, static_cast(staging)); } +void VulkanTextureCube::generate_mipmap() +{ + generate_mipmap_levels(static_cast(this)->levels); +} + +void VulkanTextureCube::fill_mipmap_blit(unsigned level, void *b) +{ + const TextureCube &self = *static_cast(this); + VkImageBlit &blit = *static_cast(b); + + int src_size = self.get_level_size(level); + int dst_size = self.get_level_size(level+1); + + blit.srcSubresource.layerCount = 6; + blit.dstSubresource.layerCount = 6; + blit.srcOffsets[1] = { src_size, src_size, 1 }; + blit.dstOffsets[1] = { dst_size, dst_size, 1 }; +} + size_t VulkanTextureCube::get_data_size() const { return 0; diff --git a/source/backends/vulkan/texturecube_backend.h b/source/backends/vulkan/texturecube_backend.h index 2e8d936f..d7730897 100644 --- a/source/backends/vulkan/texturecube_backend.h +++ b/source/backends/vulkan/texturecube_backend.h @@ -13,6 +13,8 @@ protected: virtual void fill_image_info(void *) const; void sub_image(unsigned, unsigned, int, int, unsigned, unsigned, const void *); + virtual void generate_mipmap(); + virtual void fill_mipmap_blit(unsigned, void *); public: virtual AsyncLoader *load(IO::Seekable &, const Resources * = 0) { return 0; } diff --git a/source/backends/vulkan/vulkan.cpp b/source/backends/vulkan/vulkan.cpp index b4033af9..1f697f66 100644 --- a/source/backends/vulkan/vulkan.cpp +++ b/source/backends/vulkan/vulkan.cpp @@ -77,6 +77,7 @@ VulkanFunctions::VulkanFunctions(const Graphics::VulkanContext &c): // 19 vkCmdCopyBuffer(context.get_function("vkCmdCopyBuffer")), vkCmdCopyBufferToImage(context.get_function("vkCmdCopyBufferToImage")), + vkCmdBlitImage(context.get_function("vkCmdBlitImage")), // 20 vkCmdBindIndexBuffer(context.get_function("vkCmdBindIndexBuffer")), vkCmdDrawIndexed(context.get_function("vkCmdDrawIndexed")), diff --git a/source/backends/vulkan/vulkan.h b/source/backends/vulkan/vulkan.h index b4b084bd..60de01d1 100644 --- a/source/backends/vulkan/vulkan.h +++ b/source/backends/vulkan/vulkan.h @@ -155,6 +155,7 @@ private: PFN_vkCmdPushConstants vkCmdPushConstants = 0; // 14.2.10 PFN_vkCmdCopyBuffer vkCmdCopyBuffer = 0; // 19.2 PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage = 0; // 19.4 + PFN_vkCmdBlitImage vkCmdBlitImage = 0; // 19.5 PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer = 0; // 20.3 PFN_vkCmdDrawIndexed vkCmdDrawIndexed = 0; // 20.3 PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers = 0; // 21.2 @@ -356,6 +357,9 @@ public: void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, std::uint32_t regionCount, const VkBufferImageCopy *pRegions) const { vkCmdCopyBufferToImage(handle_cast<::VkCommandBuffer>(commandBuffer), handle_cast<::VkBuffer>(srcBuffer), handle_cast<::VkImage>(dstImage), dstImageLayout, regionCount, pRegions); } + void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) const + { vkCmdBlitImage(handle_cast<::VkCommandBuffer>(commandBuffer), handle_cast<::VkImage>(srcImage), srcImageLayout, handle_cast<::VkImage>(dstImage), dstImageLayout, regionCount, pRegions, filter); } + // Chapter 20: Drawing Commands void CmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) const { vkCmdBindIndexBuffer(handle_cast<::VkCommandBuffer>(commandBuffer), handle_cast<::VkBuffer>(buffer), offset, indexType); }