copy(src, src+data_size, static_cast<char *>(staging));
}
+void VulkanTexture1D::generate_mipmap()
+{
+ generate_mipmap_levels(static_cast<const Texture1D *>(this)->levels);
+}
+
+void VulkanTexture1D::fill_mipmap_blit(unsigned level, void *b)
+{
+ const Texture1D &self = *static_cast<const Texture1D *>(this);
+ VkImageBlit &blit = *static_cast<VkImageBlit *>(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;
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; }
copy(src, src+data_size, static_cast<char *>(staging));
}
+void VulkanTexture2D::generate_mipmap()
+{
+ generate_mipmap_levels(static_cast<const Texture2D *>(this)->levels);
+}
+
+void VulkanTexture2D::fill_mipmap_blit(unsigned level, void *b)
+{
+ const Texture2D &self = *static_cast<const Texture2D *>(this);
+ VkImageBlit &blit = *static_cast<VkImageBlit *>(b);
+
+ auto src_size = self.get_level_size(level);
+ auto dst_size = self.get_level_size(level+1);
+
+ blit.srcOffsets[1] = { static_cast<int>(src_size.x), static_cast<int>(src_size.y), 1 };
+ blit.dstOffsets[1] = { static_cast<int>(dst_size.x), static_cast<int>(dst_size.y), 1 };
+}
+
Resource::AsyncLoader *VulkanTexture2D::load(IO::Seekable &, const Resources *)
{
throw logic_error("Texture2D::load is unimplemented");
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);
+#include "error.h"
#include "frameformat.h"
#include "texture2dmultisample.h"
#include "texture2dmultisample_backend.h"
image_info->samples = static_cast<VkSampleCountFlagBits>(get_vulkan_samples(self.samples));
}
+void VulkanTexture2DMultisample::generate_mipmap()
+{
+ throw invalid_operation("VulkanTexture2DMultisample::generate_mipmap");
+}
+
size_t VulkanTexture2DMultisample::get_data_size() const
{
return 0;
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; }
copy(src, src+data_size, static_cast<char *>(staging));
}
+void VulkanTexture3D::generate_mipmap()
+{
+ generate_mipmap_levels(static_cast<const Texture3D *>(this)->levels);
+}
+
+void VulkanTexture3D::fill_mipmap_blit(unsigned level, void *b)
+{
+ const Texture3D &self = *static_cast<const Texture3D *>(this);
+ VkImageBlit &blit = *static_cast<VkImageBlit *>(b);
+
+ LinAl::Vector<int, 3> src_size = self.get_level_size(level);
+ LinAl::Vector<int, 3> 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;
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;
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;
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<n_levels; ++i)
+ {
+ tq.prepare_transfer(this, true, 0,
+ [this, n_levels, i](){
+ change_layout((i==0 ? n_levels : 0), i, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, false);
+ change_layout(0, i+1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
+ },
+ [this, i](VkCommandBuffer cmd_buf, VkBuffer, size_t){
+ const VulkanFunctions &vk = device.get_functions();
+
+ VkImageBlit region = { };
+ region.srcSubresource.aspectMask = get_vulkan_aspect(get_components(static_cast<const Texture *>(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
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;
copy(src, src+data_size, static_cast<char *>(staging));
}
+void VulkanTextureCube::generate_mipmap()
+{
+ generate_mipmap_levels(static_cast<const TextureCube *>(this)->levels);
+}
+
+void VulkanTextureCube::fill_mipmap_blit(unsigned level, void *b)
+{
+ const TextureCube &self = *static_cast<const TextureCube *>(this);
+ VkImageBlit &blit = *static_cast<VkImageBlit *>(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;
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; }
// 19
vkCmdCopyBuffer(context.get_function<PFN_vkCmdCopyBuffer>("vkCmdCopyBuffer")),
vkCmdCopyBufferToImage(context.get_function<PFN_vkCmdCopyBufferToImage>("vkCmdCopyBufferToImage")),
+ vkCmdBlitImage(context.get_function<PFN_vkCmdBlitImage>("vkCmdBlitImage")),
// 20
vkCmdBindIndexBuffer(context.get_function<PFN_vkCmdBindIndexBuffer>("vkCmdBindIndexBuffer")),
vkCmdDrawIndexed(context.get_function<PFN_vkCmdDrawIndexed>("vkCmdDrawIndexed")),
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
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); }