mirror of
https://github.com/libretro/RetroArch
synced 2025-04-16 08:43:10 +00:00
Merge pull request #2741 from Themaister/master
Vulkan: Various improvements
This commit is contained in:
commit
7bb5b749a0
@ -86,6 +86,48 @@ void vulkan_map_persistent_texture(VkDevice device, struct vk_texture *texture)
|
|||||||
vkMapMemory(device, texture->memory, texture->offset, texture->size, 0, &texture->mapped);
|
vkMapMemory(device, texture->memory, texture->offset, texture->size, 0, &texture->mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||||
|
struct vk_texture *dynamic,
|
||||||
|
struct vk_texture *staging)
|
||||||
|
{
|
||||||
|
VkImageCopy region;
|
||||||
|
retro_assert(dynamic->type == VULKAN_TEXTURE_DYNAMIC);
|
||||||
|
retro_assert(staging->type == VULKAN_TEXTURE_STAGING);
|
||||||
|
|
||||||
|
vulkan_transition_texture(vk, staging);
|
||||||
|
|
||||||
|
/* We don't have to sync against previous TRANSFER, since we observed the completion
|
||||||
|
* by fences. If we have a single texture_optimal, we would need to sync against
|
||||||
|
* previous transfers to avoid races.
|
||||||
|
*
|
||||||
|
* We would also need to optionally maintain extra textures due to changes in resolution,
|
||||||
|
* so this seems like the sanest and simplest solution. */
|
||||||
|
vulkan_image_layout_transition(vk, vk->cmd, dynamic->image,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
0, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||||
|
|
||||||
|
memset(®ion, 0, sizeof(region));
|
||||||
|
region.extent.width = dynamic->width;
|
||||||
|
region.extent.height = dynamic->height;
|
||||||
|
region.extent.depth = 1;
|
||||||
|
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
region.srcSubresource.layerCount = 1;
|
||||||
|
region.dstSubresource = region.srcSubresource;
|
||||||
|
|
||||||
|
vkCmdCopyImage(vk->cmd,
|
||||||
|
staging->image, VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
dynamic->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
1, ®ion);
|
||||||
|
|
||||||
|
vulkan_image_layout_transition(vk, vk->cmd, dynamic->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);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VULKAN_DEBUG_TEXTURE_ALLOC
|
#ifdef VULKAN_DEBUG_TEXTURE_ALLOC
|
||||||
static VkImage vk_images[4 * 1024];
|
static VkImage vk_images[4 * 1024];
|
||||||
static unsigned vk_count;
|
static unsigned vk_count;
|
||||||
@ -131,25 +173,17 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
|||||||
VkFormat format,
|
VkFormat format,
|
||||||
const void *initial, const VkComponentMapping *swizzle, enum vk_texture_type type)
|
const void *initial, const VkComponentMapping *swizzle, enum vk_texture_type type)
|
||||||
{
|
{
|
||||||
/* TODO: Evaluate how we should do texture uploads on discrete cards optimally.
|
|
||||||
* For integrated GPUs, using linear texture is highly desirable to avoid extra copies, but
|
|
||||||
* we might need to take a DMA transfer with block interleave on desktop GPUs.
|
|
||||||
*
|
|
||||||
* Also, Vulkan drivers are not required to support sampling from linear textures
|
|
||||||
* (only TRANSFER), but seems to work fine on GPUs I've tested so far. */
|
|
||||||
|
|
||||||
struct vk_texture tex;
|
struct vk_texture tex;
|
||||||
VkMemoryRequirements mem_reqs;
|
VkMemoryRequirements mem_reqs;
|
||||||
VkSubresourceLayout layout;
|
VkSubresourceLayout layout;
|
||||||
VkDevice device = vk->context->device;
|
VkDevice device = vk->context->device;
|
||||||
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||||
|
VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
||||||
VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||||
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT };
|
||||||
VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT };
|
VkCommandBufferAllocateInfo cmd_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||||
|
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||||
if (type == VULKAN_TEXTURE_STATIC && !initial)
|
VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||||
retro_assert(0 && "Static textures must have initial data.\n");
|
|
||||||
|
|
||||||
memset(&tex, 0, sizeof(tex));
|
memset(&tex, 0, sizeof(tex));
|
||||||
|
|
||||||
@ -160,46 +194,104 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
|||||||
info.extent.depth = 1;
|
info.extent.depth = 1;
|
||||||
info.mipLevels = 1;
|
info.mipLevels = 1;
|
||||||
info.arrayLayers = 1;
|
info.arrayLayers = 1;
|
||||||
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
info.tiling = type != VULKAN_TEXTURE_STATIC
|
|
||||||
? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
||||||
if (type == VULKAN_TEXTURE_STATIC)
|
|
||||||
info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
if (type == VULKAN_TEXTURE_READBACK)
|
|
||||||
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
|
|
||||||
/* We'll transition this on first use for streamed textures. */
|
if (type == VULKAN_TEXTURE_STREAMED)
|
||||||
info.initialLayout = (type == VULKAN_TEXTURE_STREAMED) ?
|
{
|
||||||
VK_IMAGE_LAYOUT_PREINITIALIZED :
|
VkFormatProperties format_properties;
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED;
|
VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
||||||
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||||
|
vkGetPhysicalDeviceFormatProperties(vk->context->gpu, format, &format_properties);
|
||||||
|
|
||||||
|
if ((format_properties.linearTilingFeatures & required) != required)
|
||||||
|
{
|
||||||
|
RARCH_LOG("[Vulkan]: GPU does not support using linear images as textures. Falling back to copy path.\n");
|
||||||
|
type = VULKAN_TEXTURE_STAGING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
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.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VULKAN_TEXTURE_DYNAMIC:
|
||||||
|
retro_assert(!initial && "Dynamic textures must not have initial data.\n");
|
||||||
|
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VULKAN_TEXTURE_STREAMED:
|
||||||
|
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||||
|
info.tiling = VK_IMAGE_TILING_LINEAR;
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VULKAN_TEXTURE_STAGING:
|
||||||
|
info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
info.tiling = VK_IMAGE_TILING_LINEAR;
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VULKAN_TEXTURE_READBACK:
|
||||||
|
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
info.tiling = VK_IMAGE_TILING_LINEAR;
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
vkCreateImage(device, &info, NULL, &tex.image);
|
vkCreateImage(device, &info, NULL, &tex.image);
|
||||||
#if 0
|
#if 0
|
||||||
vulkan_track_alloc(tex.image);
|
vulkan_track_alloc(tex.image);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
|
vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
|
||||||
|
|
||||||
alloc.allocationSize = mem_reqs.size;
|
alloc.allocationSize = mem_reqs.size;
|
||||||
|
|
||||||
if (type == VULKAN_TEXTURE_STATIC)
|
switch (type)
|
||||||
{
|
{
|
||||||
alloc.memoryTypeIndex =
|
case VULKAN_TEXTURE_STATIC:
|
||||||
vulkan_find_memory_type_fallback(&vk->context->memory_properties,
|
case VULKAN_TEXTURE_DYNAMIC:
|
||||||
mem_reqs.memoryTypeBits,
|
alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
|
mem_reqs.memoryTypeBits,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties,
|
||||||
|
mem_reqs.memoryTypeBits,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/* If the texture is STREAMED and it's not DEVICE_LOCAL, we expect to hit a slower path,
|
||||||
|
* so fallback to copy path. */
|
||||||
|
if (type == VULKAN_TEXTURE_STREAMED &&
|
||||||
|
(vk->context->memory_properties.memoryTypes[alloc.memoryTypeIndex].propertyFlags &
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0)
|
||||||
{
|
{
|
||||||
alloc.memoryTypeIndex =
|
/* Recreate texture but for STAGING this time ... */
|
||||||
vulkan_find_memory_type_fallback(&vk->context->memory_properties,
|
RARCH_LOG("[Vulkan]: GPU supports linear images as textures, but not DEVICE_LOCAL. Falling back to copy path.\n");
|
||||||
|
type = VULKAN_TEXTURE_STAGING;
|
||||||
|
vkDestroyImage(device, tex.image, NULL);
|
||||||
|
info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
vkCreateImage(device, &info, NULL, &tex.image);
|
||||||
|
vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
|
||||||
|
alloc.allocationSize = mem_reqs.size;
|
||||||
|
alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties,
|
||||||
mem_reqs.memoryTypeBits,
|
mem_reqs.memoryTypeBits,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,8 +362,9 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
|||||||
tex.width = width;
|
tex.width = width;
|
||||||
tex.height = height;
|
tex.height = height;
|
||||||
tex.format = format;
|
tex.format = format;
|
||||||
|
tex.type = type;
|
||||||
|
|
||||||
if (initial && type == VULKAN_TEXTURE_STREAMED)
|
if (initial && (type == VULKAN_TEXTURE_STREAMED || type == VULKAN_TEXTURE_STAGING))
|
||||||
{
|
{
|
||||||
unsigned x, y;
|
unsigned x, y;
|
||||||
uint8_t *dst = NULL;
|
uint8_t *dst = NULL;
|
||||||
@ -293,19 +386,14 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
|
|||||||
{
|
{
|
||||||
VkImageCopy region;
|
VkImageCopy region;
|
||||||
VkCommandBuffer staging;
|
VkCommandBuffer staging;
|
||||||
VkCommandBufferAllocateInfo info = {
|
unsigned bpp = vulkan_format_to_bpp(tex.format);
|
||||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
struct vk_texture tmp = vulkan_create_texture(vk, NULL,
|
||||||
VkCommandBufferBeginInfo begin_info = {
|
width, height, format, initial, NULL, VULKAN_TEXTURE_STAGING);
|
||||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
|
||||||
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
|
||||||
unsigned bpp = vulkan_format_to_bpp(tex.format);
|
|
||||||
struct vk_texture tmp = vulkan_create_texture(vk, NULL,
|
|
||||||
width, height, format, initial, NULL, VULKAN_TEXTURE_STREAMED);
|
|
||||||
|
|
||||||
info.commandPool = vk->staging_pool;
|
cmd_info.commandPool = vk->staging_pool;
|
||||||
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
cmd_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
info.commandBufferCount = 1;
|
cmd_info.commandBufferCount = 1;
|
||||||
vkAllocateCommandBuffers(vk->context->device, &info, &staging);
|
vkAllocateCommandBuffers(vk->context->device, &cmd_info, &staging);
|
||||||
|
|
||||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
vkBeginCommandBuffer(staging, &begin_info);
|
vkBeginCommandBuffer(staging, &begin_info);
|
||||||
@ -1358,6 +1446,8 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk,
|
|||||||
/* Limit latency. */
|
/* Limit latency. */
|
||||||
if (desired_swapchain_images > 3)
|
if (desired_swapchain_images > 3)
|
||||||
desired_swapchain_images = 3;
|
desired_swapchain_images = 3;
|
||||||
|
if (desired_swapchain_images < surface_properties.minImageCount)
|
||||||
|
desired_swapchain_images = surface_properties.minImageCount;
|
||||||
|
|
||||||
if ((surface_properties.maxImageCount > 0)
|
if ((surface_properties.maxImageCount > 0)
|
||||||
&& (desired_swapchain_images > surface_properties.maxImageCount))
|
&& (desired_swapchain_images > surface_properties.maxImageCount))
|
||||||
|
@ -72,8 +72,22 @@
|
|||||||
|
|
||||||
enum vk_texture_type
|
enum vk_texture_type
|
||||||
{
|
{
|
||||||
|
/* We will use the texture as a sampled linear texture. */
|
||||||
VULKAN_TEXTURE_STREAMED = 0,
|
VULKAN_TEXTURE_STREAMED = 0,
|
||||||
|
|
||||||
|
/* We will use the texture as a linear texture, but only
|
||||||
|
* for copying to a DYNAMIC texture. */
|
||||||
|
VULKAN_TEXTURE_STAGING,
|
||||||
|
|
||||||
|
/* We will use the texture as an optimally tiled texture,
|
||||||
|
* and we will update the texture by copying from STAGING
|
||||||
|
* textures. */
|
||||||
|
VULKAN_TEXTURE_DYNAMIC,
|
||||||
|
|
||||||
|
/* We will upload content once. */
|
||||||
VULKAN_TEXTURE_STATIC,
|
VULKAN_TEXTURE_STATIC,
|
||||||
|
|
||||||
|
/* We will use the texture for reading back transfers from GPU. */
|
||||||
VULKAN_TEXTURE_READBACK
|
VULKAN_TEXTURE_READBACK
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,6 +207,7 @@ struct vk_texture
|
|||||||
uint32_t memory_type;
|
uint32_t memory_type;
|
||||||
|
|
||||||
VkImageLayout layout;
|
VkImageLayout layout;
|
||||||
|
enum vk_texture_type type;
|
||||||
bool default_smooth;
|
bool default_smooth;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -264,6 +279,7 @@ struct vk_per_frame
|
|||||||
{
|
{
|
||||||
struct vk_image backbuffer;
|
struct vk_image backbuffer;
|
||||||
struct vk_texture texture;
|
struct vk_texture texture;
|
||||||
|
struct vk_texture texture_optimal;
|
||||||
struct vk_buffer_chain vbo;
|
struct vk_buffer_chain vbo;
|
||||||
struct vk_buffer_chain ubo;
|
struct vk_buffer_chain ubo;
|
||||||
struct vk_descriptor_manager descriptor_manager;
|
struct vk_descriptor_manager descriptor_manager;
|
||||||
@ -356,6 +372,9 @@ typedef struct vk
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
struct vk_texture textures[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
struct vk_texture textures[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||||
|
struct vk_texture textures_optimal[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||||
|
bool dirty[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||||
|
|
||||||
float alpha;
|
float alpha;
|
||||||
unsigned last_index;
|
unsigned last_index;
|
||||||
bool enable;
|
bool enable;
|
||||||
@ -425,6 +444,10 @@ void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture);
|
|||||||
void vulkan_map_persistent_texture(VkDevice device, struct vk_texture *tex);
|
void vulkan_map_persistent_texture(VkDevice device, struct vk_texture *tex);
|
||||||
void vulkan_destroy_texture(VkDevice device, struct vk_texture *tex);
|
void vulkan_destroy_texture(VkDevice device, struct vk_texture *tex);
|
||||||
|
|
||||||
|
void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd,
|
||||||
|
struct vk_texture *dynamic,
|
||||||
|
struct vk_texture *staging);
|
||||||
|
|
||||||
/* VBO will be written to here. */
|
/* VBO will be written to here. */
|
||||||
void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad);
|
void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad);
|
||||||
|
|
||||||
|
@ -461,6 +461,13 @@ static void vulkan_init_textures(vk_t *vk)
|
|||||||
NULL, NULL, VULKAN_TEXTURE_STREAMED);
|
NULL, NULL, VULKAN_TEXTURE_STREAMED);
|
||||||
vulkan_map_persistent_texture(vk->context->device,
|
vulkan_map_persistent_texture(vk->context->device,
|
||||||
&vk->swapchain[i].texture);
|
&vk->swapchain[i].texture);
|
||||||
|
|
||||||
|
if (vk->swapchain[i].texture.type == VULKAN_TEXTURE_STAGING)
|
||||||
|
{
|
||||||
|
vk->swapchain[i].texture_optimal = vulkan_create_texture(vk, NULL,
|
||||||
|
vk->tex_w, vk->tex_h, vk->tex_fmt,
|
||||||
|
NULL, NULL, VULKAN_TEXTURE_DYNAMIC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -471,9 +478,12 @@ static void vulkan_deinit_textures(vk_t *vk)
|
|||||||
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for (i = 0; i < vk->num_swapchain_images; i++)
|
for (i = 0; i < vk->num_swapchain_images; i++)
|
||||||
|
{
|
||||||
if (vk->swapchain[i].texture.memory != VK_NULL_HANDLE)
|
if (vk->swapchain[i].texture.memory != VK_NULL_HANDLE)
|
||||||
vulkan_destroy_texture(vk->context->device,
|
vulkan_destroy_texture(vk->context->device, &vk->swapchain[i].texture);
|
||||||
&vk->swapchain[i].texture);
|
if (vk->swapchain[i].texture_optimal.memory != VK_NULL_HANDLE)
|
||||||
|
vulkan_destroy_texture(vk->context->device, &vk->swapchain[i].texture_optimal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vulkan_deinit_command_buffers(vk_t *vk)
|
static void vulkan_deinit_command_buffers(vk_t *vk)
|
||||||
@ -671,9 +681,12 @@ static void vulkan_deinit_menu(vk_t *vk)
|
|||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
|
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
|
||||||
|
{
|
||||||
if (vk->menu.textures[i].memory)
|
if (vk->menu.textures[i].memory)
|
||||||
vulkan_destroy_texture(vk->context->device,
|
vulkan_destroy_texture(vk->context->device, &vk->menu.textures[i]);
|
||||||
&vk->menu.textures[i]);
|
if (vk->menu.textures_optimal[i].memory)
|
||||||
|
vulkan_destroy_texture(vk->context->device, &vk->menu.textures_optimal[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vulkan_free(void *data)
|
static void vulkan_free(void *data)
|
||||||
@ -1323,6 +1336,13 @@ static bool vulkan_frame(void *data, const void *frame,
|
|||||||
vulkan_buffer_chain_discard(&chain->vbo);
|
vulkan_buffer_chain_discard(&chain->vbo);
|
||||||
vulkan_buffer_chain_discard(&chain->ubo);
|
vulkan_buffer_chain_discard(&chain->ubo);
|
||||||
|
|
||||||
|
/* Start recording the command buffer. */
|
||||||
|
vk->cmd = chain->cmd;
|
||||||
|
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
vkResetCommandBuffer(vk->cmd, 0);
|
||||||
|
vkBeginCommandBuffer(vk->cmd, &begin_info);
|
||||||
|
memset(&vk->tracker, 0, sizeof(vk->tracker));
|
||||||
|
|
||||||
/* Upload texture */
|
/* Upload texture */
|
||||||
retro_perf_start(©_frame);
|
retro_perf_start(©_frame);
|
||||||
if (frame && !vk->hw.enable)
|
if (frame && !vk->hw.enable)
|
||||||
@ -1336,9 +1356,16 @@ static bool vulkan_frame(void *data, const void *frame,
|
|||||||
|| chain->texture.height != frame_height)
|
|| chain->texture.height != frame_height)
|
||||||
{
|
{
|
||||||
chain->texture = vulkan_create_texture(vk, &chain->texture,
|
chain->texture = vulkan_create_texture(vk, &chain->texture,
|
||||||
frame_width, frame_height, chain->texture.format,
|
frame_width, frame_height, chain->texture.format, NULL, NULL,
|
||||||
NULL, NULL, VULKAN_TEXTURE_STREAMED);
|
chain->texture_optimal.memory ? VULKAN_TEXTURE_STAGING : VULKAN_TEXTURE_STREAMED);
|
||||||
vulkan_map_persistent_texture(vk->context->device, &chain->texture);
|
vulkan_map_persistent_texture(vk->context->device, &chain->texture);
|
||||||
|
|
||||||
|
if (chain->texture.type == VULKAN_TEXTURE_STAGING)
|
||||||
|
{
|
||||||
|
chain->texture_optimal = vulkan_create_texture(vk, &chain->texture_optimal,
|
||||||
|
frame_width, frame_height, chain->texture_optimal.format,
|
||||||
|
NULL, NULL, VULKAN_TEXTURE_DYNAMIC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame != chain->texture.mapped)
|
if (frame != chain->texture.mapped)
|
||||||
@ -1352,17 +1379,17 @@ static bool vulkan_frame(void *data, const void *frame,
|
|||||||
memcpy(dst, src, frame_width * bpp);
|
memcpy(dst, src, frame_width * bpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we have an optimal texture, copy to that now. */
|
||||||
|
if (chain->texture_optimal.memory != VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vulkan_copy_staging_to_dynamic(vk, vk->cmd,
|
||||||
|
&chain->texture_optimal, &chain->texture);
|
||||||
|
}
|
||||||
|
|
||||||
vk->last_valid_index = frame_index;
|
vk->last_valid_index = frame_index;
|
||||||
}
|
}
|
||||||
retro_perf_stop(©_frame);
|
retro_perf_stop(©_frame);
|
||||||
|
|
||||||
/* Start recording the command buffer. */
|
|
||||||
vk->cmd = chain->cmd;
|
|
||||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
vkResetCommandBuffer(vk->cmd, 0);
|
|
||||||
vkBeginCommandBuffer(vk->cmd, &begin_info);
|
|
||||||
memset(&vk->tracker, 0, sizeof(vk->tracker));
|
|
||||||
|
|
||||||
/* Notify filter chain about the new sync index. */
|
/* Notify filter chain about the new sync index. */
|
||||||
vulkan_filter_chain_notify_sync_index(vk->filter_chain, frame_index);
|
vulkan_filter_chain_notify_sync_index(vk->filter_chain, frame_index);
|
||||||
|
|
||||||
@ -1399,9 +1426,11 @@ static bool vulkan_frame(void *data, const void *frame,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct vk_texture *tex = &
|
struct vk_texture *tex = &vk->swapchain[vk->last_valid_index].texture;
|
||||||
vk->swapchain[vk->last_valid_index].texture;
|
if (vk->swapchain[vk->last_valid_index].texture_optimal.memory != VK_NULL_HANDLE)
|
||||||
vulkan_transition_texture(vk, tex);
|
tex = &vk->swapchain[vk->last_valid_index].texture_optimal;
|
||||||
|
else
|
||||||
|
vulkan_transition_texture(vk, tex);
|
||||||
|
|
||||||
input.view = tex->view;
|
input.view = tex->view;
|
||||||
input.layout = tex->layout;
|
input.layout = tex->layout;
|
||||||
@ -1450,16 +1479,30 @@ static bool vulkan_frame(void *data, const void *frame,
|
|||||||
if (vk->menu.textures[vk->menu.last_index].image != VK_NULL_HANDLE)
|
if (vk->menu.textures[vk->menu.last_index].image != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
struct vk_draw_quad quad;
|
struct vk_draw_quad quad;
|
||||||
|
struct vk_texture *optimal = &vk->menu.textures_optimal[vk->menu.last_index];
|
||||||
vulkan_set_viewport(vk, width, height, vk->menu.full_screen, false);
|
vulkan_set_viewport(vk, width, height, vk->menu.full_screen, false);
|
||||||
|
|
||||||
quad.pipeline = vk->pipelines.alpha_blend;
|
quad.pipeline = vk->pipelines.alpha_blend;
|
||||||
quad.texture = &vk->menu.textures[vk->menu.last_index];
|
quad.texture = &vk->menu.textures[vk->menu.last_index];
|
||||||
quad.sampler = vk->samplers.linear;
|
|
||||||
quad.mvp = &vk->mvp_no_rot;
|
if (optimal->memory != VK_NULL_HANDLE)
|
||||||
quad.color.r = 1.0f;
|
{
|
||||||
quad.color.g = 1.0f;
|
if (vk->menu.dirty[vk->menu.last_index])
|
||||||
quad.color.b = 1.0f;
|
{
|
||||||
quad.color.a = vk->menu.alpha;
|
vulkan_copy_staging_to_dynamic(vk, vk->cmd,
|
||||||
|
optimal,
|
||||||
|
quad.texture);
|
||||||
|
vk->menu.dirty[vk->menu.last_index] = false;
|
||||||
|
}
|
||||||
|
quad.texture = optimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
quad.sampler = vk->samplers.linear;
|
||||||
|
quad.mvp = &vk->mvp_no_rot;
|
||||||
|
quad.color.r = 1.0f;
|
||||||
|
quad.color.g = 1.0f;
|
||||||
|
quad.color.b = 1.0f;
|
||||||
|
quad.color.a = vk->menu.alpha;
|
||||||
vulkan_draw_quad(vk, &quad);
|
vulkan_draw_quad(vk, &quad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1657,6 +1700,13 @@ static bool vulkan_get_current_sw_framebuffer(void *data,
|
|||||||
framebuffer->width, framebuffer->height, chain->texture.format,
|
framebuffer->width, framebuffer->height, chain->texture.format,
|
||||||
NULL, NULL, VULKAN_TEXTURE_STREAMED);
|
NULL, NULL, VULKAN_TEXTURE_STREAMED);
|
||||||
vulkan_map_persistent_texture(vk->context->device, &chain->texture);
|
vulkan_map_persistent_texture(vk->context->device, &chain->texture);
|
||||||
|
|
||||||
|
if (chain->texture.type == VULKAN_TEXTURE_STAGING)
|
||||||
|
{
|
||||||
|
chain->texture_optimal = vulkan_create_texture(vk, &chain->texture_optimal,
|
||||||
|
framebuffer->width, framebuffer->height, chain->texture_optimal.format,
|
||||||
|
NULL, NULL, VULKAN_TEXTURE_DYNAMIC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
framebuffer->data = chain->texture.mapped;
|
framebuffer->data = chain->texture.mapped;
|
||||||
@ -1690,9 +1740,10 @@ static void vulkan_set_texture_frame(void *data,
|
|||||||
{
|
{
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
unsigned x, y;
|
unsigned x, y;
|
||||||
vk_t *vk = (vk_t*)data;
|
vk_t *vk = (vk_t*)data;
|
||||||
unsigned index = vk->context->current_swapchain_index;
|
unsigned index = vk->context->current_swapchain_index;
|
||||||
struct vk_texture *texture = &vk->menu.textures[index];
|
struct vk_texture *texture = &vk->menu.textures[index];
|
||||||
|
struct vk_texture *texture_optimal = &vk->menu.textures_optimal[index];
|
||||||
const VkComponentMapping br_swizzle = {
|
const VkComponentMapping br_swizzle = {
|
||||||
VK_COMPONENT_SWIZZLE_B,
|
VK_COMPONENT_SWIZZLE_B,
|
||||||
VK_COMPONENT_SWIZZLE_G,
|
VK_COMPONENT_SWIZZLE_G,
|
||||||
@ -1709,7 +1760,8 @@ static void vulkan_set_texture_frame(void *data,
|
|||||||
texture->memory ? texture : NULL,
|
texture->memory ? texture : NULL,
|
||||||
width, height,
|
width, height,
|
||||||
rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_B4G4R4A4_UNORM_PACK16,
|
rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_B4G4R4A4_UNORM_PACK16,
|
||||||
NULL, rgb32 ? NULL : &br_swizzle, VULKAN_TEXTURE_STREAMED);
|
NULL, rgb32 ? NULL : &br_swizzle,
|
||||||
|
texture_optimal->memory ? VULKAN_TEXTURE_STAGING : VULKAN_TEXTURE_STREAMED);
|
||||||
|
|
||||||
vkMapMemory(vk->context->device, texture->memory,
|
vkMapMemory(vk->context->device, texture->memory,
|
||||||
texture->offset, texture->size, 0, (void**)&ptr);
|
texture->offset, texture->size, 0, (void**)&ptr);
|
||||||
@ -1723,6 +1775,18 @@ static void vulkan_set_texture_frame(void *data,
|
|||||||
vkUnmapMemory(vk->context->device, texture->memory);
|
vkUnmapMemory(vk->context->device, texture->memory);
|
||||||
vk->menu.alpha = alpha;
|
vk->menu.alpha = alpha;
|
||||||
vk->menu.last_index = index;
|
vk->menu.last_index = index;
|
||||||
|
|
||||||
|
if (texture->type == VULKAN_TEXTURE_STAGING)
|
||||||
|
{
|
||||||
|
*texture_optimal = vulkan_create_texture(vk,
|
||||||
|
texture_optimal->memory ? texture_optimal : NULL,
|
||||||
|
width, height,
|
||||||
|
rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_B4G4R4A4_UNORM_PACK16,
|
||||||
|
NULL, rgb32 ? NULL : &br_swizzle,
|
||||||
|
VULKAN_TEXTURE_DYNAMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk->menu.dirty[index] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vulkan_set_texture_enable(void *data, bool state, bool full_screen)
|
static void vulkan_set_texture_enable(void *data, bool state, bool full_screen)
|
||||||
|
@ -182,14 +182,30 @@ static void menu_display_vk_draw_bg(void *data)
|
|||||||
|
|
||||||
static void menu_display_vk_restore_clear_color(void)
|
static void menu_display_vk_restore_clear_color(void)
|
||||||
{
|
{
|
||||||
//glClearColor(0.0f, 0.0f, 0.0f, 0.00f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menu_display_vk_clear_color(void *data)
|
static void menu_display_vk_clear_color(void *data)
|
||||||
{
|
{
|
||||||
(void)data;
|
VkClearRect rect;
|
||||||
/* FIXME: This makes little sense in Vulkan.
|
VkClearAttachment attachment = { VK_IMAGE_ASPECT_COLOR_BIT };
|
||||||
* We shouldn't be clearing mid-screen nilly willy. */
|
menu_display_ctx_clearcolor_t *clearcolor =
|
||||||
|
(menu_display_ctx_clearcolor_t*)data;
|
||||||
|
|
||||||
|
vk_t *vk = vk_get_ptr();
|
||||||
|
if (!vk || !clearcolor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
attachment.clearValue.color.float32[0] = clearcolor->r;
|
||||||
|
attachment.clearValue.color.float32[1] = clearcolor->g;
|
||||||
|
attachment.clearValue.color.float32[2] = clearcolor->b;
|
||||||
|
attachment.clearValue.color.float32[3] = clearcolor->a;
|
||||||
|
|
||||||
|
memset(&rect, 0, sizeof(rect));
|
||||||
|
rect.rect.extent.width = vk->context->swapchain_width;
|
||||||
|
rect.rect.extent.height = vk->context->swapchain_height;
|
||||||
|
rect.layerCount = 1;
|
||||||
|
|
||||||
|
vkCmdClearAttachments(vk->cmd, 1, &attachment, 1, &rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float *menu_display_vk_get_tex_coords(void)
|
static const float *menu_display_vk_get_tex_coords(void)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user