diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 909710c3bc..acad033225 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -157,6 +157,7 @@ void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd, retro_assert(dynamic->type == VULKAN_TEXTURE_DYNAMIC); retro_assert(staging->type == VULKAN_TEXTURE_STAGING); + vulkan_sync_texture_to_gpu(vk, staging); vulkan_transition_texture(vk, staging); /* We don't have to sync against previous TRANSFER, @@ -240,6 +241,30 @@ static void vulkan_track_dealloc(VkImage image) } #endif +void vulkan_sync_texture_to_gpu(vk_t *vk, const struct vk_texture *tex) +{ + VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; + if (!tex || !tex->need_manual_cache_management || tex->memory == VK_NULL_HANDLE) + return; + + range.memory = tex->memory; + range.offset = 0; + range.size = VK_WHOLE_SIZE; + vkFlushMappedMemoryRanges(vk->context->device, 1, &range); +} + +void vulkan_sync_texture_to_cpu(vk_t *vk, const struct vk_texture *tex) +{ + VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE }; + if (!tex || !tex->need_manual_cache_management || tex->memory == VK_NULL_HANDLE) + return; + + range.memory = tex->memory; + range.offset = 0; + range.size = VK_WHOLE_SIZE; + vkInvalidateMappedMemoryRanges(vk->context->device, 1, &range); +} + struct vk_texture vulkan_create_texture(vk_t *vk, struct vk_texture *old, unsigned width, unsigned height, @@ -340,14 +365,18 @@ struct vk_texture vulkan_create_texture(vk_t *vk, break; default: + /* Try to find a memory type which is cached, even if it means manual cache management. */ 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); + + tex.need_manual_cache_management = + (vk->context->memory_properties.memoryTypes[alloc.memoryTypeIndex].propertyFlags & + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0; break; } @@ -472,6 +501,7 @@ struct vk_texture vulkan_create_texture(vk_t *vk, for (y = 0; y < tex.height; y++, dst += tex.stride, src += stride) memcpy(dst, src, width * bpp); + vulkan_sync_texture_to_gpu(vk, &tex); vkUnmapMemory(device, tex.memory); } else if (initial && type == VULKAN_TEXTURE_STATIC) diff --git a/gfx/common/vulkan_common.h b/gfx/common/vulkan_common.h index 7e69ca3e7c..92d63dc382 100644 --- a/gfx/common/vulkan_common.h +++ b/gfx/common/vulkan_common.h @@ -170,6 +170,7 @@ struct vk_texture VkImageLayout layout; enum vk_texture_type type; bool default_smooth; + bool need_manual_cache_management; }; struct vk_buffer @@ -406,6 +407,9 @@ struct vk_texture vulkan_create_texture(vk_t *vk, const void *initial, const VkComponentMapping *swizzle, enum vk_texture_type type); +void vulkan_sync_texture_to_gpu(vk_t *vk, const struct vk_texture *tex); +void vulkan_sync_texture_to_cpu(vk_t *vk, const struct vk_texture *tex); + void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture); void vulkan_transfer_image_ownership(VkCommandBuffer cmd, diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index 7016c5ae45..7d9aa2a689 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -1448,22 +1448,6 @@ static void vulkan_readback(vk_t *vk) VK_PIPELINE_STAGE_HOST_BIT); } -static void vulkan_flush_caches(vk_t *vk) -{ - VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER }; - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT; - - vkCmdPipelineBarrier(vk->cmd, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - false, - 1, &barrier, - 0, NULL, 0, NULL); -} - static bool vulkan_frame(void *data, const void *frame, unsigned frame_width, unsigned frame_height, uint64_t frame_count, @@ -1522,8 +1506,6 @@ static bool vulkan_frame(void *data, const void *frame, memset(&vk->tracker, 0, sizeof(vk->tracker)); - vulkan_flush_caches(vk); - waits_for_semaphores = vk->hw.enable && frame && !vk->hw.num_cmd && vk->hw.valid_semaphore; @@ -1591,6 +1573,8 @@ static bool vulkan_frame(void *data, const void *frame, vulkan_copy_staging_to_dynamic(vk, vk->cmd, &chain->texture_optimal, &chain->texture); } + else + vulkan_sync_texture_to_gpu(vk, &chain->texture); vk->last_valid_index = frame_index; } @@ -2016,6 +2000,7 @@ static void vulkan_set_texture_frame(void *data, for (y = 0; y < height; y++, dst += texture->stride, src += stride) memcpy(dst, src, stride); + vulkan_sync_texture_to_gpu(vk, texture); vkUnmapMemory(vk->context->device, texture->memory); vk->menu.alpha = alpha; @@ -2164,6 +2149,8 @@ static bool vulkan_read_viewport(void *data, uint8_t *buffer) vkMapMemory(vk->context->device, staging->memory, staging->offset, staging->size, 0, (void**)&src); + vulkan_sync_texture_to_cpu(vk, staging); + vk->readback.scaler.in_stride = staging->stride; vk->readback.scaler.out_stride = -(int)vk->vp.width * 3; scaler_ctx_scale(&vk->readback.scaler, buffer, src); @@ -2187,6 +2174,8 @@ static bool vulkan_read_viewport(void *data, uint8_t *buffer) vulkan_map_persistent_texture( vk->context->device, staging); + vulkan_sync_texture_to_cpu(vk, staging); + { unsigned x, y; const uint8_t *src = (const uint8_t*)staging->mapped;