venus: move feedback on empty last batch to prior batch

For submissions with an empty last batch containing no cmd buffers but
with semaphores as zink does, adding feedback to that batch would make
it no longer empty and increase submission overhead on some drivers.

Since feedback order is enforced by barriers, the feedback cmds can
instead be appended to the previous batch (if it exists) so that the
last batch remains empty.

Signed-off-by: Juston Li <justonli@google.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27830>
This commit is contained in:
Juston Li 2024-02-26 16:43:27 -08:00 committed by Marge Bot
parent 0586a3fb22
commit e57cf175e2
3 changed files with 85 additions and 2 deletions

View file

@ -395,6 +395,11 @@ vn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
instance->enable_wsi_multi_plane_modifiers ? "yes" : "no");
}
const char *engine_name = instance->base.base.app_info.engine_name;
if (engine_name) {
instance->engine_is_zink = strcmp(engine_name, "mesa zink") == 0;
}
*pInstance = instance_handle;
return VK_SUCCESS;

View file

@ -69,6 +69,8 @@ struct vn_instance {
uint32_t renderer_api_version;
uint32_t renderer_version;
bool engine_is_zink;
struct {
mtx_t mutex;
bool initialized;

View file

@ -21,6 +21,7 @@
#include "vn_device.h"
#include "vn_device_memory.h"
#include "vn_feedback.h"
#include "vn_instance.h"
#include "vn_physical_device.h"
#include "vn_query_pool.h"
#include "vn_renderer.h"
@ -42,6 +43,7 @@ struct vn_queue_submission {
uint32_t cmd_count;
uint32_t feedback_types;
bool has_zink_sync_batch;
const struct vn_device_memory *wsi_mem;
struct vn_sync_payload_external external_payload;
@ -256,6 +258,62 @@ vn_get_signal_semaphore_counter(struct vn_queue_submission *submit,
}
}
static bool
vn_has_zink_sync_batch(struct vn_queue_submission *submit)
{
struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle);
struct vn_device *dev = (void *)queue->base.base.base.device;
struct vn_instance *instance = dev->instance;
const uint32_t last_batch_index = submit->batch_count - 1;
if (!instance->engine_is_zink)
return false;
if (!submit->batch_count || !last_batch_index ||
vn_get_cmd_count(submit, last_batch_index))
return false;
if (vn_get_wait_semaphore_count(submit, last_batch_index))
return false;
const uint32_t signal_count =
vn_get_signal_semaphore_count(submit, last_batch_index);
for (uint32_t i = 0; i < signal_count; i++) {
struct vn_semaphore *sem = vn_semaphore_from_handle(
vn_get_signal_semaphore(submit, last_batch_index, i));
if (sem->feedback.slot) {
return true;
}
}
return false;
}
static bool
vn_fix_batch_cmd_count_for_zink_sync(struct vn_queue_submission *submit,
uint32_t batch_index,
uint32_t new_cmd_count)
{
/* If the last batch is a zink sync batch which is empty but contains
* feedback, append the feedback to the previous batch instead so that
* the last batch remains empty for perf.
*/
if (batch_index == submit->batch_count - 1 &&
submit->has_zink_sync_batch) {
if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) {
VkSubmitInfo2 *batch =
&submit->temp.submit2_batches[batch_index - 1];
assert(batch->pCommandBufferInfos);
batch->commandBufferInfoCount += new_cmd_count;
} else {
VkSubmitInfo *batch = &submit->temp.submit_batches[batch_index - 1];
assert(batch->pCommandBuffers);
batch->commandBufferCount += new_cmd_count;
}
return true;
}
return false;
}
static bool
vn_semaphore_wait_external(struct vn_device *dev, struct vn_semaphore *sem);
@ -340,8 +398,16 @@ vn_queue_submission_count_batch_feedback(struct vn_queue_submission *submit,
submit->cmd_count++;
}
if (feedback_types)
/* Space to copy the original cmds to append feedback to it.
* If the last batch is a zink sync batch which is an empty batch with
* sem feedback, feedback will be appended to the second to last batch
* so also need to copy the second to last batch's original cmds even
* if it doesn't have feedback itself.
*/
if (feedback_types || (batch_index == submit->batch_count - 2 &&
submit->has_zink_sync_batch)) {
submit->cmd_count += cmd_count;
}
}
submit->feedback_types |= feedback_types;
@ -357,6 +423,9 @@ vn_queue_submission_prepare(struct vn_queue_submission *submit)
if (fence && fence->feedback.slot)
submit->feedback_types |= VN_FEEDBACK_TYPE_FENCE;
if (submit->batch_type != VK_STRUCTURE_TYPE_BIND_SPARSE_INFO)
submit->has_zink_sync_batch = vn_has_zink_sync_batch(submit);
submit->external_payload.ring_idx = queue->ring_idx;
submit->wsi_mem = NULL;
@ -640,6 +709,9 @@ vn_queue_submission_add_feedback_cmds(struct vn_queue_submission *submit,
if (result != VK_SUCCESS)
return result;
}
if (vn_fix_batch_cmd_count_for_zink_sync(submit, batch_index,
new_cmd_count))
return VK_SUCCESS;
}
if (feedback_types & VN_FEEDBACK_TYPE_FENCE) {
@ -696,8 +768,12 @@ vn_queue_submission_setup_batch(struct vn_queue_submission *submit,
/* If the batch has qfb, sfb or ffb, copy the original commands and append
* feedback cmds.
* If this is the second to last batch and the last batch a zink sync batch
* which is empty but has feedback, also copy the original commands for
* this batch so that the last batch's feedback can be appended to it.
*/
if (extra_cmd_count) {
if (extra_cmd_count || (batch_index == submit->batch_count - 2 &&
submit->has_zink_sync_batch)) {
const size_t cmd_size = vn_get_cmd_size(submit);
const size_t total_cmd_size = cmd_count * cmd_size;
/* copy only needed for non-empty batches */