diff --git a/interfaces/Crafter.Graphics-ImageVulkan.cppm b/interfaces/Crafter.Graphics-ImageVulkan.cppm index 9a51331..a423c1b 100644 --- a/interfaces/Crafter.Graphics-ImageVulkan.cppm +++ b/interfaces/Crafter.Graphics-ImageVulkan.cppm @@ -32,18 +32,19 @@ export namespace Crafter { template class ImageVulkan { public: - std::uint32_t width; - std::uint32_t height; + std::uint16_t width; + std::uint16_t height; + std::uint8_t mipLevels; VkImage image; VkDeviceMemory imageMemory; VulkanBuffer buffer; VkImageView imageView; VkDescriptorImageInfo descriptor; - void Create(std::uint32_t width, std::uint32_t height, VkCommandBuffer cmd, VkFormat format) { + void Create(std::uint16_t width, std::uint16_t height, std::uint8_t mipLevels, VkCommandBuffer cmd, VkFormat format) { this->width = width; this->height = height; - + this->mipLevels = mipLevels; buffer.Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, width * height); VkImageCreateInfo imageInfo = {}; @@ -52,12 +53,12 @@ export namespace Crafter { imageInfo.extent.width = width; imageInfo.extent.height = height; imageInfo.extent.depth = 1; - imageInfo.mipLevels = 5; + imageInfo.mipLevels = mipLevels; imageInfo.arrayLayers = 1; imageInfo.format = format; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; // Include TRANSFER_SRC_BIT + imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -81,20 +82,19 @@ export namespace Crafter { viewInfo.format = format; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 5; + viewInfo.subresourceRange.levelCount = mipLevels; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; Device::CheckVkResult(vkCreateImageView(Device::device, &viewInfo, nullptr, &imageView)); // Final transition to shader read-only layout - TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, 5); + TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, mipLevels); } - void Update(const PixelType* bufferdata, VkCommandBuffer cmd) { - std::memcpy(buffer.value, bufferdata, height*width*sizeof(PixelType)); + void Update(VkCommandBuffer cmd) { buffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, 5); + TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, mipLevels); VkBufferImageCopy region{}; region.bufferOffset = 0; @@ -115,39 +115,37 @@ export namespace Crafter { ®ion ); - //Transition source and destination mip levels to correct layout - TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 1); + if(mipLevels > 0) { + TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 1); - // Mipmap generation (now includes the correct layout and offset management) - for (std::uint32_t i = 1; i < 5; ++i) { - std::uint32_t mipWidth = std::max(1u, width >> i); - std::uint32_t mipHeight = std::max(1u, height >> i); + for (std::uint16_t i = 1; i < mipLevels; ++i) { + std::uint16_t mipWidth = width >> i; + std::uint16_t mipHeight = height >> i; - std::uint32_t previousMipWidth = std::max(1u, width >> (i - 1)); - std::uint32_t previousMipHeight = std::max(1u, height >> (i - 1)); + std::uint16_t previousMipWidth = width >> (i - std::uint16_t(1)); + std::uint16_t previousMipHeight = height >> (i - std::uint16_t(1)); - VkImageBlit blit = {}; - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = 1; - blit.srcOffsets[0] = { 0, 0, 0 }; // Ensure srcOffsets[0] is 0 - blit.srcOffsets[1] = { (int32_t)previousMipWidth, (int32_t)previousMipHeight, 1 }; + VkImageBlit blit = {}; + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.mipLevel = i - 1; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = 1; + blit.srcOffsets[0] = { 0, 0, 0 }; + blit.srcOffsets[1] = { (int32_t)previousMipWidth, (int32_t)previousMipHeight, 1 }; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = 1; - blit.dstOffsets[0] = { 0, 0, 0 }; // Ensure dstOffsets[0] is 0 - blit.dstOffsets[1] = { (int32_t)mipWidth, (int32_t)mipHeight, 1 }; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.mipLevel = i; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = 1; + blit.dstOffsets[0] = { 0, 0, 0 }; + blit.dstOffsets[1] = { (int32_t)mipWidth, (int32_t)mipHeight, 1 }; - vkCmdBlitImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); - - // Transition back after blitting - TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, i, 1); + vkCmdBlitImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); + TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, i, 1); + } } - TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, 5); + TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, mipLevels); } private: