Mesa (master): radv: Add image sparse memory update implementation.

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Jan 11 12:20:21 UTC 2021


Module: Mesa
Branch: master
Commit: 3ac880482933b728428e12a46867b2d51ba8a15a
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=3ac880482933b728428e12a46867b2d51ba8a15a

Author: Bas Nieuwenhuizen <bas at basnieuwenhuizen.nl>
Date:   Sun Dec  6 19:17:03 2020 +0100

radv: Add image sparse memory update implementation.

Reviewed-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7953>

---

 src/amd/vulkan/radv_device.c | 109 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 108 insertions(+), 1 deletion(-)

diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index 6d4b83580eb..2dc59e04746 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -4294,6 +4294,83 @@ radv_sparse_image_opaque_bind_memory(struct radv_device *device,
 	return VK_SUCCESS;
 }
 
+static VkResult
+radv_sparse_image_bind_memory(struct radv_device *device,
+                              const VkSparseImageMemoryBindInfo *bind)
+{
+	RADV_FROM_HANDLE(radv_image, image, bind->image);
+	struct radeon_surf *surface = &image->planes[0].surface;
+	uint32_t bs = vk_format_get_blocksize(image->vk_format);
+	VkResult result;
+
+	for (uint32_t i = 0; i < bind->bindCount; ++i) {
+		struct radv_device_memory *mem = NULL;
+		uint32_t offset, pitch;
+		uint32_t mem_offset = bind->pBinds[i].memoryOffset;
+		const uint32_t layer = bind->pBinds[i].subresource.arrayLayer;
+		const uint32_t level = bind->pBinds[i].subresource.mipLevel;
+
+		VkExtent3D bind_extent = bind->pBinds[i].extent;
+		bind_extent.width = DIV_ROUND_UP(bind_extent.width, vk_format_get_blockwidth(image->vk_format));
+		bind_extent.height = DIV_ROUND_UP(bind_extent.height, vk_format_get_blockheight(image->vk_format));
+
+		VkOffset3D bind_offset = bind->pBinds[i].offset;
+		bind_offset.x /= vk_format_get_blockwidth(image->vk_format);
+		bind_offset.y /= vk_format_get_blockheight(image->vk_format);
+
+		if (bind->pBinds[i].memory != VK_NULL_HANDLE)
+			mem = radv_device_memory_from_handle(bind->pBinds[i].memory);
+
+		if (device->physical_device->rad_info.chip_class >= GFX9) {
+			offset = surface->u.gfx9.surf_slice_size * layer +
+			         surface->u.gfx9.prt_level_offset[level];
+			pitch = surface->u.gfx9.prt_level_pitch[level];
+		} else {
+			offset = surface->u.legacy.level[level].offset +
+			         surface->u.legacy.level[level].slice_size_dw * 4 * layer;
+			pitch = surface->u.legacy.level[level].nblk_x;
+		}
+
+		offset += (bind_offset.y * pitch * bs) +
+		          (bind_offset.x * surface->prt_tile_height * bs);
+
+		uint32_t aligned_extent_width = ALIGN(bind_extent.width,
+		                                      surface->prt_tile_width);
+
+		bool whole_subres = bind_offset.x == 0 &&
+		                    aligned_extent_width == pitch;
+
+		if (whole_subres) {
+			uint32_t aligned_extent_height = ALIGN(bind_extent.height,
+			                                       surface->prt_tile_height);
+
+			uint32_t size = aligned_extent_width * aligned_extent_height * bs;
+			result = device->ws->buffer_virtual_bind(image->bo,
+			                                         offset,
+			                                         size,
+			                                         mem ? mem->bo : NULL,
+			                                         mem_offset);
+			if (result != VK_SUCCESS)
+				return result;
+		} else {
+			uint32_t img_increment = pitch * bs;
+			uint32_t mem_increment = aligned_extent_width * bs;
+			uint32_t size = mem_increment * surface->prt_tile_height;
+			for (unsigned y = 0; y < bind_extent.height; y += surface->prt_tile_height) {
+				result = device->ws->buffer_virtual_bind(image->bo,
+				                                         offset + img_increment * y,
+				                                         size,
+				                                         mem ? mem->bo : NULL,
+				                                         mem_offset + mem_increment * y);
+				if (result != VK_SUCCESS)
+					return result;
+			}
+		}
+	}
+
+	return VK_SUCCESS;
+}
+
 static VkResult
 radv_get_preambles(struct radv_queue *queue,
                    const VkCommandBuffer *cmd_buffers,
@@ -4346,6 +4423,8 @@ struct radv_deferred_queue_submission {
 	uint32_t buffer_bind_count;
 	VkSparseImageOpaqueMemoryBindInfo *image_opaque_binds;
 	uint32_t image_opaque_bind_count;
+	VkSparseImageMemoryBindInfo *image_binds;
+	uint32_t image_bind_count;
 
 	bool flush_caches;
 	VkShaderStageFlags wait_dst_stage_mask;
@@ -4377,6 +4456,8 @@ struct radv_queue_submission {
 	uint32_t buffer_bind_count;
 	const VkSparseImageOpaqueMemoryBindInfo *image_opaque_binds;
 	uint32_t image_opaque_bind_count;
+	const VkSparseImageMemoryBindInfo *image_binds;
+	uint32_t image_bind_count;
 
 	bool flush_caches;
 	VkPipelineStageFlags wait_dst_stage_mask;
@@ -4415,6 +4496,11 @@ radv_create_deferred_submission(struct radv_queue *queue,
 	size += submission->cmd_buffer_count * sizeof(VkCommandBuffer);
 	size += submission->buffer_bind_count * sizeof(VkSparseBufferMemoryBindInfo);
 	size += submission->image_opaque_bind_count * sizeof(VkSparseImageOpaqueMemoryBindInfo);
+	size += submission->image_bind_count * sizeof(VkSparseImageMemoryBindInfo);
+
+	for (uint32_t i = 0; i < submission->image_bind_count; ++i)
+		size += submission->image_binds[i].bindCount * sizeof(VkSparseImageMemoryBind);
+
 	size += submission->wait_semaphore_count * sizeof(struct radv_semaphore_part *);
 	size += temporary_count * sizeof(struct radv_semaphore_part);
 	size += submission->signal_semaphore_count * sizeof(struct radv_semaphore_part *);
@@ -4449,10 +4535,22 @@ radv_create_deferred_submission(struct radv_queue *queue,
 		       submission->image_opaque_bind_count * sizeof(*deferred->image_opaque_binds));
 	}
 
+	deferred->image_binds = (void*)(deferred->image_opaque_binds + deferred->image_opaque_bind_count);
+	deferred->image_bind_count = submission->image_bind_count;
+
+	VkSparseImageMemoryBind *sparse_image_binds = (void*)(deferred->image_binds + deferred->image_bind_count);
+	for (uint32_t i = 0; i < deferred->image_bind_count; ++i) {
+		deferred->image_binds[i] = submission->image_binds[i];
+		deferred->image_binds[i].pBinds = sparse_image_binds;
+
+		for (uint32_t j = 0; j < deferred->image_binds[i].bindCount; ++j)
+			*sparse_image_binds++ = submission->image_binds[i].pBinds[j];
+	}
+
 	deferred->flush_caches = submission->flush_caches;
 	deferred->wait_dst_stage_mask = submission->wait_dst_stage_mask;
 
-	deferred->wait_semaphores = (void*)(deferred->image_opaque_binds + deferred->image_opaque_bind_count);
+	deferred->wait_semaphores = (void*)sparse_image_binds;
 	deferred->wait_semaphore_count = submission->wait_semaphore_count;
 
 	deferred->signal_semaphores = (void*)(deferred->wait_semaphores + deferred->wait_semaphore_count);
@@ -4631,6 +4729,13 @@ radv_queue_submit_deferred(struct radv_deferred_queue_submission *submission,
 			goto fail;
 	}
 
+	for (uint32_t i = 0; i < submission->image_bind_count; ++i) {
+		result = radv_sparse_image_bind_memory(queue->device,
+						       submission->image_binds + i);
+		if (result != VK_SUCCESS)
+			goto fail;
+	}
+
 	if (!submission->cmd_buffer_count) {
 		result = queue->device->ws->cs_submit(ctx, queue->queue_idx,
 						      &queue->device->empty_cs[queue->queue_family_index],
@@ -5721,6 +5826,8 @@ static bool radv_sparse_bind_has_effects(const VkBindSparseInfo *info)
 				.buffer_bind_count = pBindInfo[i].bufferBindCount,
 				.image_opaque_binds = pBindInfo[i].pImageOpaqueBinds,
 				.image_opaque_bind_count = pBindInfo[i].imageOpaqueBindCount,
+				.image_binds = pBindInfo[i].pImageBinds,
+				.image_bind_count = pBindInfo[i].imageBindCount,
 				.wait_semaphores = pBindInfo[i].pWaitSemaphores,
 				.wait_semaphore_count = pBindInfo[i].waitSemaphoreCount,
 				.signal_semaphores = pBindInfo[i].pSignalSemaphores,



More information about the mesa-commit mailing list