|
|
@ -1026,8 +1026,6 @@ void ComputeAndGraphics::createTextureImage() { |
|
|
|
stbi_uc* pixels = stbi_load(TEXTURE_PATH.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); |
|
|
|
VkDeviceSize imageSize = texWidth * texHeight * 4; |
|
|
|
|
|
|
|
_mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1; |
|
|
|
|
|
|
|
if (!pixels) { |
|
|
|
throw std::runtime_error("failed to load texture image!"); |
|
|
|
} |
|
|
@ -1039,19 +1037,16 @@ void ComputeAndGraphics::createTextureImage() { |
|
|
|
|
|
|
|
stbi_image_free(pixels); |
|
|
|
|
|
|
|
createImage(texWidth, texHeight, _mipLevels, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL |
|
|
|
, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
|
|
createImage(texWidth, texHeight, 1, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL |
|
|
|
, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
|
|
, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, _textureImage, _textureImageMemory); |
|
|
|
|
|
|
|
transitionImageLayout(_textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, _mipLevels); |
|
|
|
transitionImageLayout(_textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1); |
|
|
|
copyBufferToImage(stagingBuffer, _textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight)); |
|
|
|
|
|
|
|
// transitionImageLayout(_textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, _mipLevels);
|
|
|
|
transitionImageLayout(_textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 1); |
|
|
|
|
|
|
|
vkDestroyBuffer(_device, stagingBuffer, nullptr); |
|
|
|
vkFreeMemory(_device, stagingBufferMemory, nullptr); |
|
|
|
|
|
|
|
generateMipmaps(_textureImage, VK_FORMAT_R8G8B8A8_SRGB, texWidth, texHeight, _mipLevels); |
|
|
|
} |
|
|
|
|
|
|
|
void ComputeAndGraphics::copyImageToStagingBuffer(VkBuffer& stagingBuffer, VkDeviceMemory& stagingBufferMemory, stbi_uc* pixels, VkDeviceSize imageSize) |
|
|
@ -1065,119 +1060,6 @@ void ComputeAndGraphics::copyImageToStagingBuffer(VkBuffer& stagingBuffer, VkDev |
|
|
|
vkUnmapMemory(_device, stagingBufferMemory); |
|
|
|
} |
|
|
|
|
|
|
|
void ComputeAndGraphics::generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels) { |
|
|
|
VkFormatProperties formatProperties; |
|
|
|
vkGetPhysicalDeviceFormatProperties(_physicalDevice, imageFormat, &formatProperties); |
|
|
|
|
|
|
|
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) { |
|
|
|
throw std::runtime_error("texture image format does not support linear blitting!"); |
|
|
|
} |
|
|
|
|
|
|
|
VkCommandBuffer commandBuffer = beginSingleTimeCommands(); |
|
|
|
|
|
|
|
VkImageMemoryBarrier barrier = initMipmapBarrier(image); |
|
|
|
int32_t mipWidth = texWidth; |
|
|
|
int32_t mipHeight = texHeight; |
|
|
|
|
|
|
|
for (uint32_t i = 1; i < mipLevels; i++) { |
|
|
|
setFirstStepMipmapBarrierInfo(barrier, i); |
|
|
|
vkCmdPipelineBarrier(commandBuffer, |
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, |
|
|
|
0, nullptr, |
|
|
|
0, nullptr, |
|
|
|
1, &barrier); |
|
|
|
|
|
|
|
VkImageBlit blit = createBlitMipMapInfo(mipWidth, mipHeight, i); |
|
|
|
vkCmdBlitImage(commandBuffer, |
|
|
|
image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
|
|
|
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
|
|
|
1, &blit, |
|
|
|
VK_FILTER_LINEAR); |
|
|
|
|
|
|
|
|
|
|
|
setSecondStepMipmapBarrierInfo(barrier, i); |
|
|
|
vkCmdPipelineBarrier(commandBuffer, |
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, |
|
|
|
0, nullptr, |
|
|
|
0, nullptr, |
|
|
|
1, &barrier); |
|
|
|
|
|
|
|
if (mipWidth > 1) mipWidth /= 2; |
|
|
|
if (mipHeight > 1) mipHeight /= 2; |
|
|
|
} |
|
|
|
|
|
|
|
setLastStepMipmapBarrierInfo(barrier, mipLevels - 1); |
|
|
|
|
|
|
|
vkCmdPipelineBarrier(commandBuffer, |
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, |
|
|
|
0, nullptr, |
|
|
|
0, nullptr, |
|
|
|
1, &barrier); |
|
|
|
|
|
|
|
endSingleTimeCommands(commandBuffer); |
|
|
|
} |
|
|
|
|
|
|
|
VkImageMemoryBarrier ComputeAndGraphics::initMipmapBarrier(VkImage image) |
|
|
|
{ |
|
|
|
VkImageMemoryBarrier barrier{}; |
|
|
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; |
|
|
|
barrier.image = image; |
|
|
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
|
|
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; |
|
|
|
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
|
|
|
barrier.subresourceRange.baseArrayLayer = 0; |
|
|
|
barrier.subresourceRange.layerCount = 1; |
|
|
|
barrier.subresourceRange.levelCount = 1; |
|
|
|
|
|
|
|
return barrier; |
|
|
|
} |
|
|
|
|
|
|
|
void ComputeAndGraphics::setFirstStepMipmapBarrierInfo(VkImageMemoryBarrier& barrier, uint32_t index) |
|
|
|
{ |
|
|
|
barrier.subresourceRange.baseMipLevel = index - 1; |
|
|
|
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
|
|
|
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
|
|
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
|
|
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
|
|
|
} |
|
|
|
|
|
|
|
void ComputeAndGraphics::setSecondStepMipmapBarrierInfo(VkImageMemoryBarrier& barrier, uint32_t index) |
|
|
|
{ |
|
|
|
barrier.subresourceRange.baseMipLevel = index - 1; |
|
|
|
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; |
|
|
|
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
|
|
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; |
|
|
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
|
|
|
} |
|
|
|
|
|
|
|
void ComputeAndGraphics::setLastStepMipmapBarrierInfo(VkImageMemoryBarrier& barrier, uint32_t index) |
|
|
|
{ |
|
|
|
barrier.subresourceRange.baseMipLevel = index; |
|
|
|
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; |
|
|
|
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
|
|
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; |
|
|
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; |
|
|
|
} |
|
|
|
|
|
|
|
VkImageBlit ComputeAndGraphics::createBlitMipMapInfo(int32_t mipWidth, int32_t mipHeight, uint32_t index) |
|
|
|
{ |
|
|
|
VkImageBlit blit{}; |
|
|
|
blit.srcOffsets[0] = { 0, 0, 0 }; |
|
|
|
blit.srcOffsets[1] = {mipWidth, mipHeight, 1}; |
|
|
|
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
|
|
|
blit.srcSubresource.mipLevel = index - 1; |
|
|
|
blit.srcSubresource.baseArrayLayer = 0; |
|
|
|
blit.srcSubresource.layerCount = 1; |
|
|
|
blit.dstOffsets[0] = { 0, 0, 0 }; |
|
|
|
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 }; |
|
|
|
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
|
|
|
blit.dstSubresource.mipLevel = index; |
|
|
|
blit.dstSubresource.baseArrayLayer = 0; |
|
|
|
blit.dstSubresource.layerCount = 1; |
|
|
|
|
|
|
|
return blit; |
|
|
|
} |
|
|
|
|
|
|
|
void ComputeAndGraphics::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels) |
|
|
|
{ |
|
|
|
VkCommandBuffer commandBuffer = beginSingleTimeCommands(); |
|
|
@ -1256,7 +1138,7 @@ void ComputeAndGraphics::setSrcAndDst(VkImageMemoryBarrier& barrier, VkPipelineS |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void ComputeAndGraphics::createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits /*numSamples*/, VkFormat format |
|
|
|
void ComputeAndGraphics::createImage(uint32_t width, uint32_t height, uint32_t /*mipLevels*/, VkSampleCountFlagBits /*numSamples*/, VkFormat format |
|
|
|
, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image |
|
|
|
, VkDeviceMemory& imageMemory) |
|
|
|
{ |
|
|
@ -1266,7 +1148,7 @@ void ComputeAndGraphics::createImage(uint32_t width, uint32_t height, uint32_t m |
|
|
|
imageInfo.extent.width = static_cast<uint32_t>(width); |
|
|
|
imageInfo.extent.height = static_cast<uint32_t>(height); |
|
|
|
imageInfo.extent.depth = 1; |
|
|
|
imageInfo.mipLevels = mipLevels; |
|
|
|
imageInfo.mipLevels = 1; |
|
|
|
imageInfo.arrayLayers = 1; |
|
|
|
imageInfo.format = format; |
|
|
|
imageInfo.tiling = tiling; |
|
|
@ -1342,7 +1224,7 @@ VkBufferImageCopy ComputeAndGraphics::createBufferImageCopyInfo(uint32_t width, |
|
|
|
|
|
|
|
void ComputeAndGraphics::createTextureImageView() |
|
|
|
{ |
|
|
|
_textureImageView = createImageView(_textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, _mipLevels); |
|
|
|
_textureImageView = createImageView(_textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, 1); |
|
|
|
} |
|
|
|
|
|
|
|
VkImageView ComputeAndGraphics::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels) |
|
|
@ -1389,7 +1271,7 @@ void ComputeAndGraphics::createTextureSampler() |
|
|
|
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; |
|
|
|
samplerInfo.mipLodBias = 0.0f; |
|
|
|
samplerInfo.minLod = 0.0f; |
|
|
|
samplerInfo.maxLod = static_cast<float>(_mipLevels); |
|
|
|
samplerInfo.maxLod = 1.0; |
|
|
|
|
|
|
|
if (vkCreateSampler(_device, &samplerInfo, nullptr, &_textureSampler) != VK_SUCCESS) { |
|
|
|
throw std::runtime_error("failed to create texture sampler!"); |
|
|
|