mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
Vulkan: Add mipmapping support.
This commit is contained in:
parent
e57997bb82
commit
4e8e79eabd
@ -265,6 +265,18 @@ void vulkan_sync_texture_to_cpu(vk_t *vk, const struct vk_texture *tex)
|
||||
vkInvalidateMappedMemoryRanges(vk->context->device, 1, &range);
|
||||
}
|
||||
|
||||
static unsigned vulkan_num_miplevels(unsigned width, unsigned height)
|
||||
{
|
||||
unsigned size = width > height ? width : height;
|
||||
unsigned levels = 0;
|
||||
while (size)
|
||||
{
|
||||
levels++;
|
||||
size >>= 1;
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
struct vk_texture *old,
|
||||
unsigned width, unsigned height,
|
||||
@ -284,6 +296,7 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
VkCommandBufferAllocateInfo cmd_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
unsigned i;
|
||||
|
||||
memset(&tex, 0, sizeof(tex));
|
||||
|
||||
@ -292,8 +305,19 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
info.extent.width = width;
|
||||
info.extent.height = height;
|
||||
info.extent.depth = 1;
|
||||
info.mipLevels = 1;
|
||||
info.arrayLayers = 1;
|
||||
|
||||
/* For simplicity, always build mipmaps for
|
||||
* static textures, samplers can be used to enable it dynamically.
|
||||
*/
|
||||
if (type == VULKAN_TEXTURE_STATIC)
|
||||
{
|
||||
info.mipLevels = vulkan_num_miplevels(width, height);
|
||||
tex.mipmap = true;
|
||||
}
|
||||
else
|
||||
info.mipLevels = 1;
|
||||
|
||||
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
if (type == VULKAN_TEXTURE_STREAMED)
|
||||
@ -317,7 +341,9 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
case VULKAN_TEXTURE_STATIC:
|
||||
retro_assert(initial && "Static textures must have initial data.\n");
|
||||
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
break;
|
||||
|
||||
@ -545,13 +571,80 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ®ion);
|
||||
|
||||
vulkan_image_layout_transition(vk, staging, tex.image,
|
||||
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);
|
||||
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;
|
||||
unsigned src_width = MAX(width >> (i - 1), 1);
|
||||
unsigned src_height = MAX(height >> (i - 1), 1);
|
||||
unsigned target_width = MAX(width >> i, 1);
|
||||
unsigned target_height = MAX(height >> i, 1);
|
||||
memset(&blit_region, 0, sizeof(blit_region));
|
||||
|
||||
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;
|
||||
|
||||
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. */
|
||||
vulkan_image_layout_transition(vk, staging, tex.image,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
vulkan_image_layout_transition(vk, staging, tex.image,
|
||||
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);
|
||||
}
|
||||
|
||||
vkEndCommandBuffer(staging);
|
||||
submit_info.commandBufferCount = 1;
|
||||
|
@ -173,6 +173,7 @@ struct vk_texture
|
||||
enum vk_texture_type type;
|
||||
bool default_smooth;
|
||||
bool need_manual_cache_management;
|
||||
bool mipmap;
|
||||
};
|
||||
|
||||
struct vk_buffer
|
||||
@ -352,6 +353,8 @@ typedef struct vk
|
||||
{
|
||||
VkSampler linear;
|
||||
VkSampler nearest;
|
||||
VkSampler mipmap_nearest;
|
||||
VkSampler mipmap_linear;
|
||||
} samplers;
|
||||
|
||||
unsigned last_valid_index;
|
||||
|
@ -483,16 +483,31 @@ static void vulkan_init_samplers(vk_t *vk)
|
||||
vkCreateSampler(vk->context->device,
|
||||
&info, NULL, &vk->samplers.nearest);
|
||||
|
||||
info.magFilter = VK_FILTER_LINEAR;
|
||||
info.minFilter = VK_FILTER_LINEAR;
|
||||
info.magFilter = VK_FILTER_LINEAR;
|
||||
info.minFilter = VK_FILTER_LINEAR;
|
||||
vkCreateSampler(vk->context->device,
|
||||
&info, NULL, &vk->samplers.linear);
|
||||
|
||||
info.maxLod = VK_LOD_CLAMP_NONE;
|
||||
info.magFilter = VK_FILTER_NEAREST;
|
||||
info.minFilter = VK_FILTER_NEAREST;
|
||||
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
vkCreateSampler(vk->context->device,
|
||||
&info, NULL, &vk->samplers.mipmap_nearest);
|
||||
|
||||
info.magFilter = VK_FILTER_LINEAR;
|
||||
info.minFilter = VK_FILTER_LINEAR;
|
||||
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
vkCreateSampler(vk->context->device,
|
||||
&info, NULL, &vk->samplers.mipmap_linear);
|
||||
}
|
||||
|
||||
static void vulkan_deinit_samplers(vk_t *vk)
|
||||
{
|
||||
vkDestroySampler(vk->context->device, vk->samplers.nearest, NULL);
|
||||
vkDestroySampler(vk->context->device, vk->samplers.linear, NULL);
|
||||
vkDestroySampler(vk->context->device, vk->samplers.mipmap_nearest, NULL);
|
||||
vkDestroySampler(vk->context->device, vk->samplers.mipmap_linear, NULL);
|
||||
}
|
||||
|
||||
static void vulkan_init_buffers(vk_t *vk)
|
||||
@ -1749,7 +1764,9 @@ static bool vulkan_frame(void *data, const void *frame,
|
||||
quad.texture = optimal;
|
||||
}
|
||||
|
||||
quad.sampler = vk->samplers.linear;
|
||||
quad.sampler = optimal->mipmap ?
|
||||
vk->samplers.mipmap_linear : vk->samplers.linear;
|
||||
|
||||
quad.mvp = &vk->mvp_no_rot;
|
||||
quad.color.r = 1.0f;
|
||||
quad.color.g = 1.0f;
|
||||
@ -2137,10 +2154,9 @@ static uintptr_t vulkan_load_texture(void *video_data, void *data,
|
||||
image->width, image->height, VK_FORMAT_B8G8R8A8_UNORM,
|
||||
image->pixels, NULL, VULKAN_TEXTURE_STATIC);
|
||||
|
||||
/* TODO: Actually add mipmapping support.
|
||||
* Optimal tiling would make sense here as well ... */
|
||||
texture->default_smooth =
|
||||
filter_type == TEXTURE_FILTER_MIPMAP_LINEAR || filter_type == TEXTURE_FILTER_LINEAR;
|
||||
texture->mipmap = filter_type == TEXTURE_FILTER_MIPMAP_LINEAR;
|
||||
|
||||
return (uintptr_t)texture;
|
||||
}
|
||||
@ -2370,7 +2386,8 @@ static void vulkan_render_overlay(vk_t *vk)
|
||||
memset(&call, 0, sizeof(call));
|
||||
call.pipeline = vk->display.pipelines[3]; /* Strip with blend */
|
||||
call.texture = &vk->overlay.images[i];
|
||||
call.sampler = vk->samplers.linear;
|
||||
call.sampler = call.texture->mipmap ?
|
||||
vk->samplers.mipmap_linear : vk->samplers.linear;
|
||||
call.uniform = &vk->mvp;
|
||||
call.uniform_size = sizeof(vk->mvp);
|
||||
call.vbo = ⦥
|
||||
|
@ -193,8 +193,9 @@ static void menu_display_vk_draw(void *data)
|
||||
vk->display.pipelines[
|
||||
to_display_pipeline(draw->prim_type, vk->display.blend)],
|
||||
texture,
|
||||
texture->default_smooth
|
||||
? vk->samplers.linear : vk->samplers.nearest,
|
||||
texture->mipmap ?
|
||||
vk->samplers.mipmap_linear :
|
||||
(texture->default_smooth ? vk->samplers.linear : vk->samplers.nearest),
|
||||
draw->matrix_data
|
||||
? draw->matrix_data : menu_display_vk_get_default_mvp(),
|
||||
sizeof(math_matrix_4x4),
|
||||
|
Loading…
x
Reference in New Issue
Block a user