diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index b2f88b8ccd..2bba8d71e6 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -552,8 +552,13 @@ struct vk_texture vulkan_create_texture(vk_t *vk, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + /* If doing mipmapping on upload, keep in general so we can easily do transfers to + * and transfers from the images without having to + * mess around with lots of extra transitions at per-level granularity. + */ vulkan_image_layout_transition(vk, staging, tex.image, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_UNDEFINED, + tex.mipmap ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); @@ -568,23 +573,12 @@ struct vk_texture vulkan_create_texture(vk_t *vk, vkCmdCopyImage(staging, tmp.image, VK_IMAGE_LAYOUT_GENERAL, - tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + tex.image, + tex.mipmap ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); if (tex.mipmap) { - /* Keep in general so we can easily do transfers to - * and transfers from the images without having to - * mess around with lots of extra transitions at per-level granularity. - */ - vulkan_image_layout_transition(vk, staging, tex.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT); - for (i = 1; i < info.mipLevels; i++) { VkImageBlit blit_region; @@ -607,23 +601,20 @@ struct vk_texture vulkan_create_texture(vk_t *vk, blit_region.dstOffsets[1].y = target_height; blit_region.dstOffsets[1].z = 1; + /* Only injects execution and memory barriers, + * not actual transition. */ + vulkan_image_layout_transition(vk, staging, tex.image, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkCmdBlitImage(staging, tex.image, VK_IMAGE_LAYOUT_GENERAL, tex.image, VK_IMAGE_LAYOUT_GENERAL, 1, &blit_region, VK_FILTER_LINEAR); - - if (i + 1 < info.mipLevels) - { - /* Only injects execution and memory barriers, - * not actual transition. */ - vulkan_image_layout_transition(vk, staging, tex.image, - VK_IMAGE_LAYOUT_GENERAL, - VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_TRANSFER_READ_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT); - } } /* Complete our texture. */ diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp index a4eef530e0..a78967f88a 100644 --- a/gfx/drivers_shader/shader_vulkan.cpp +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -186,7 +186,10 @@ class StaticTexture VkImageView view, VkDeviceMemory memory, unique_ptr buffer, - unsigned width, unsigned height); + unsigned width, unsigned height, + bool linear, + bool mipmap, + vulkan_filter_chain_address address); ~StaticTexture(); StaticTexture(StaticTexture&&) = delete; @@ -1091,7 +1094,10 @@ StaticTexture::StaticTexture(string id, VkImageView view, VkDeviceMemory memory, unique_ptr buffer, - unsigned width, unsigned height) + unsigned width, unsigned height, + bool linear, + bool mipmap, + vulkan_filter_chain_address address) : id(move(id)), device(device), image(image), @@ -1099,9 +1105,10 @@ StaticTexture::StaticTexture(string id, memory(memory), buffer(move(buffer)) { - texture.filter = VULKAN_FILTER_CHAIN_LINEAR; - texture.mip_filter = VULKAN_FILTER_CHAIN_NEAREST; - texture.address = VULKAN_FILTER_CHAIN_ADDRESS_REPEAT; + texture.filter = linear ? VULKAN_FILTER_CHAIN_LINEAR : VULKAN_FILTER_CHAIN_NEAREST; + texture.mip_filter = + mipmap && linear ? VULKAN_FILTER_CHAIN_LINEAR : VULKAN_FILTER_CHAIN_NEAREST; + texture.address = address; texture.texture.image = image; texture.texture.view = view; texture.texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -2316,6 +2323,37 @@ static VkFormat glslang_format_to_vk(glslang_format fmt) } } +static unsigned num_miplevels(unsigned width, unsigned height) +{ + unsigned size = std::max(width, height); + unsigned levels = 0; + while (size) + { + levels++; + size >>= 1; + } + return levels; +} + +static vulkan_filter_chain_address wrap_to_address(gfx_wrap_type type) +{ + switch (type) + { + default: + case RARCH_WRAP_BORDER: + return VULKAN_FILTER_CHAIN_ADDRESS_CLAMP_TO_BORDER; + + case RARCH_WRAP_EDGE: + return VULKAN_FILTER_CHAIN_ADDRESS_CLAMP_TO_EDGE; + + case RARCH_WRAP_REPEAT: + return VULKAN_FILTER_CHAIN_ADDRESS_REPEAT; + + case RARCH_WRAP_MIRRORED_REPEAT: + return VULKAN_FILTER_CHAIN_ADDRESS_MIRRORED_REPEAT; + } +} + static unique_ptr vulkan_filter_chain_load_lut(VkCommandBuffer cmd, const struct vulkan_filter_chain_create_info *info, vulkan_filter_chain *chain, @@ -2341,7 +2379,7 @@ static unique_ptr vulkan_filter_chain_load_lut(VkCommandBuffer cm image_info.extent.width = image.width; image_info.extent.height = image.height; image_info.extent.depth = 1; - image_info.mipLevels = 1; + image_info.mipLevels = shader->mipmap ? num_miplevels(image.width, image.height) : 1; image_info.arrayLayers = 1; image_info.samples = VK_SAMPLE_COUNT_1_BIT; image_info.tiling = VK_IMAGE_TILING_OPTIMAL; @@ -2370,7 +2408,7 @@ static unique_ptr vulkan_filter_chain_load_lut(VkCommandBuffer cm view_info.components.b = VK_COMPONENT_SWIZZLE_B; view_info.components.a = VK_COMPONENT_SWIZZLE_A; view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.levelCount = image_info.mipLevels; view_info.subresourceRange.layerCount = 1; vkCreateImageView(info->device, &view_info, nullptr, &view); @@ -2381,7 +2419,8 @@ static unique_ptr vulkan_filter_chain_load_lut(VkCommandBuffer cm buffer->unmap(); image_layout_transition(cmd, tex, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_UNDEFINED, + shader->mipmap ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); @@ -2393,11 +2432,50 @@ static unique_ptr vulkan_filter_chain_load_lut(VkCommandBuffer cm region.imageExtent.height = image.height; region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(cmd, buffer->get_buffer(), tex, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + vkCmdCopyBufferToImage(cmd, buffer->get_buffer(), tex, + shader->mipmap ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + for (unsigned i = 1; i < image_info.mipLevels; i++) + { + VkImageBlit blit_region = {}; + unsigned src_width = std::max(image.width >> (i - 1), 1u); + unsigned src_height = std::max(image.height >> (i - 1), 1u); + unsigned target_width = std::max(image.width >> i, 1u); + unsigned target_height = std::max(image.height >> i, 1u); + + blit_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit_region.srcSubresource.mipLevel = i - 1; + blit_region.srcSubresource.baseArrayLayer = 0; + blit_region.srcSubresource.layerCount = 1; + blit_region.dstSubresource = blit_region.srcSubresource; + blit_region.dstSubresource.mipLevel = i; + blit_region.srcOffsets[1].x = src_width; + blit_region.srcOffsets[1].y = src_height; + blit_region.srcOffsets[1].z = 1; + blit_region.dstOffsets[1].x = target_width; + blit_region.dstOffsets[1].y = target_height; + blit_region.dstOffsets[1].z = 1; + + // Only injects execution and memory barriers, + // not actual transition. + image_layout_transition(cmd, tex, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + + vkCmdBlitImage(cmd, + tex, VK_IMAGE_LAYOUT_GENERAL, + tex, VK_IMAGE_LAYOUT_GENERAL, + 1, &blit_region, VK_FILTER_LINEAR); + } + image_layout_transition(cmd, tex, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + shader->mipmap ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); @@ -2405,7 +2483,10 @@ static unique_ptr vulkan_filter_chain_load_lut(VkCommandBuffer cm image.pixels = nullptr; return unique_ptr(new StaticTexture(shader->id, info->device, - tex, view, memory, move(buffer), image.width, image.height)); + tex, view, memory, move(buffer), image.width, image.height, + shader->filter != RARCH_FILTER_NEAREST, + image_info.mipLevels > 1, + wrap_to_address(shader->wrap))); error: if (image.pixels)