diff --git a/include/vulkan/image.hpp b/include/vulkan/image.hpp index d6a5c2d..33e82da 100644 --- a/include/vulkan/image.hpp +++ b/include/vulkan/image.hpp @@ -14,9 +14,13 @@ public: ~Image(); VkImageView createView(VkImageAspectFlags aspectFlags); + VkSampler createSampler(); VkImage handle = VK_NULL_HANDLE; VkImageView view = VK_NULL_HANDLE; + VkSampler sampler = VK_NULL_HANDLE; + uint32_t width; + uint32_t height; private: VkFormat format; void transitionLayout(VkImageLayout oldLayout, VkImageLayout newLayout); diff --git a/src/application.cpp b/src/application.cpp index ce7074d..6baf3f7 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -107,6 +107,7 @@ Application::Application() { u_char* data = new u_char[imageSize]; memset(data, 0xFF, imageSize); Image image(data, imageSize, w, h, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + image.createSampler(); } descriptorPool->bindBuffer(*cameraUniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::WORLD, 0); diff --git a/src/vulkan/buffer.cpp b/src/vulkan/buffer.cpp index 588a4a2..318301a 100644 --- a/src/vulkan/buffer.cpp +++ b/src/vulkan/buffer.cpp @@ -53,7 +53,25 @@ void Buffer::copyTo(Buffer *buffer) { } void Buffer::copyTo(Image *image) { + VkQueue queue = Instance::instance->graphicsAndPresentQueue; + CommandPool* commandPool = Instance::instance->renderingCommandPool; + + VkCommandBuffer commandBuffer = commandPool->beginSingleTimeCommandBuffer(); + VkBufferImageCopy region {}; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {image->width, image->height, 1}; + region.imageSubresource.layerCount = 1; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + vkCmdCopyBufferToImage(commandBuffer, handle, image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + commandPool->endSingleTimeCommandBuffer(commandBuffer, queue); } void Buffer::setName(const std::string &name) { diff --git a/src/vulkan/image.cpp b/src/vulkan/image.cpp index efecea7..571ad00 100644 --- a/src/vulkan/image.cpp +++ b/src/vulkan/image.cpp @@ -1,10 +1,10 @@ #include "vulkan/image.hpp" #include "vulkan/instance.hpp" #include "vulkan/buffer.hpp" - +#include "vulkan/command_pool.hpp" Image::Image(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, - VkImageUsageFlags usage) : format(format) { + VkImageUsageFlags usage) : format(format), width(width), height(height) { VkImageCreateInfo imageCreateInfo {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -30,14 +30,20 @@ Image::Image(uint32_t width, uint32_t height, VkFormat format, VkImageTiling til Image::Image(void *initialData, VkDeviceSize size, uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage) : Image(width, height, format, tiling, usage){ + Buffer stagingBuffer(size, initialData, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); + transitionLayout(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); stagingBuffer.copyTo(this); + + transitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } Image::~Image() { if (view) vkDestroyImageView(Instance::GetDevice(), view, nullptr); + if (sampler) + vkDestroySampler(Instance::GetDevice(), sampler, nullptr); vmaDestroyImage(Instance::GetAllocator(), handle, allocation); } @@ -61,6 +67,73 @@ VkImageView Image::createView(VkImageAspectFlags aspectFlags) { return view; } +VkSampler Image::createSampler() { + VkSamplerCreateInfo samplerInfo {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0; + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0; + samplerInfo.maxLod = 0.0; + + vkCreateSampler(Instance::GetDevice(), &samplerInfo, nullptr, &sampler); + + return sampler; +} + void Image::transitionLayout(VkImageLayout oldLayout, VkImageLayout newLayout) { + auto commandPool = Instance::instance->renderingCommandPool; + auto commandBuffer = commandPool->beginSingleTimeCommandBuffer(); + + VkImageMemoryBarrier barrier {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = handle; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + + VkPipelineStageFlags sourceStage = 0; + VkPipelineStageFlags destinationStage = 0; + + if ((oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL){ + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL){ + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } + + vkCmdPipelineBarrier(commandBuffer, + sourceStage, destinationStage, + 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + commandPool->endSingleTimeCommandBuffer(commandBuffer, Instance::instance->graphicsAndPresentQueue); }