mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 02:08:22 -10:00
(Vulkan) Android presents on the graphics queue
Since5d950a7288the frontend presents on the graphics family's second queue wherever the family has one. Behind Android's WSI the loader turns a present's wait semaphore into a sync fd through the driver's QueueSignalReleaseImageANDROID, and Mali (G615 MC6, r44p1, which reports two queues in family 0) fails that call when the semaphore was signalled on another queue: every present fails, the failed present destroys the swapchain, the next acquire rebuilds it, and the menu freezes in that loop (#19601). A CI build from before3df4bd91b7- the swapchain-teardown hazard fixed in4823918abe- already froze, so that fix alone does not cover it. The choice is made in one place now, vulkan_select_present_queue_index(): queue 1 where the family has a second queue, queue 0 behind Android's WSI. Android's WSI is VULKAN_WSI_ANDROID, and any context driver in an ANDROID build, the SDL3 one included. A core that provides its own presentation queue in the graphics family gets the graphics queue there as well; one in another family is still refused as before. The desktop drivers keep the second queue and its lock-free presents. The vulkan_validation sample checks the policy ahead of its display check, so it runs on every lane: second queue elsewhere, the graphics queue behind Android's WSI at one, two and four queues. The old selection behind the same helper fails it on the Android cases.
This commit is contained in:
1 parent
4823918abe
commit
c265d78ee9
3 files changed
+93
-5
No files matched your search
@@ -804,6 +804,25 @@ static VkDevice vulkan_context_create_device_wrapper(
|
||||
return device;
|
||||
}
|
||||
|
||||
uint32_t vulkan_select_present_queue_index(bool android_wsi,
|
||||
uint32_t family_queue_count)
|
||||
{
|
||||
if (android_wsi)
|
||||
return 0;
|
||||
return (family_queue_count >= 2) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Android's WSI, whichever context driver brought the surface up - the
|
||||
* SDL3 one reaches the same loader there. */
|
||||
static bool vulkan_wsi_is_android(const gfx_ctx_vulkan_data_t *vk)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
return true;
|
||||
#else
|
||||
return vk->wsi_type == VULKAN_WSI_ANDROID;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
|
||||
{
|
||||
uint32_t queue_count;
|
||||
@@ -936,8 +955,18 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
|
||||
context.queue_family_index);
|
||||
return false;
|
||||
}
|
||||
vk->context.present_queue = context.presentation_queue;
|
||||
RARCH_LOG("[Vulkan] Core provided a separate presentation queue.\n");
|
||||
/* Same family, so the graphics queue can present to the
|
||||
* surface as well; behind Android's WSI it does, rather
|
||||
* than the core's second queue (see the declaration of
|
||||
* vulkan_select_present_queue_index()). */
|
||||
if (vulkan_select_present_queue_index(
|
||||
vulkan_wsi_is_android(vk), 2))
|
||||
{
|
||||
vk->context.present_queue = context.presentation_queue;
|
||||
RARCH_LOG("[Vulkan] Core provided a separate presentation queue.\n");
|
||||
}
|
||||
else
|
||||
RARCH_LOG("[Vulkan] Core provided a separate presentation queue; presenting on the graphics queue under Android's WSI.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1024,9 +1053,11 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
|
||||
RARCH_LOG("[Vulkan] Queue family %u supports %u sub-queues.\n",
|
||||
i, queue_properties[i].queueCount);
|
||||
/* A second queue of the family, when there is one, takes
|
||||
* the presents off the graphics queue and its lock. */
|
||||
if (queue_properties[i].queueCount >= 2)
|
||||
present_queue_index = 1;
|
||||
* the presents off the graphics queue and its lock - except
|
||||
* behind Android's WSI; see the declaration. */
|
||||
present_queue_index = vulkan_select_present_queue_index(
|
||||
vulkan_wsi_is_android(vk),
|
||||
queue_properties[i].queueCount);
|
||||
found_queue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -418,6 +418,15 @@ void vulkan_debug_mark_buffer(VkDevice device, VkBuffer buffer);
|
||||
bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
|
||||
enum vulkan_wsi_type type);
|
||||
|
||||
/* Which queue of the graphics family the frontend presents on: 1 when
|
||||
* the family has a second queue, so presents stay off the graphics
|
||||
* queue and its lock, and 0 otherwise. Always 0 behind Android's WSI:
|
||||
* there the loader turns a present's semaphore wait into a sync fd
|
||||
* through the driver's QueueSignalReleaseImageANDROID, and Mali fails
|
||||
* that call for a semaphore signalled on another queue (#19601). */
|
||||
uint32_t vulkan_select_present_queue_index(bool android_wsi,
|
||||
uint32_t family_queue_count);
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* Returns the version string of the MoltenVK implementation in use,
|
||||
* captured at Vulkan context creation. Returns an empty string if no
|
||||
|
||||
@@ -659,11 +659,59 @@ static int test_memory_type_selection(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The present-queue policy (#19601): the frontend presents on the
|
||||
* family's second queue where there is one, except behind Android's
|
||||
* WSI, where Mali fails QueueSignalReleaseImageANDROID for a present
|
||||
* whose semaphore another queue signalled - every present failed, the
|
||||
* swapchain was rebuilt each frame and the menu froze. The Android WSI
|
||||
* cannot run here, so the policy is checked where it is decided. Needs
|
||||
* no device or display. */
|
||||
static int test_present_queue_policy(void)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
bool android;
|
||||
uint32_t count;
|
||||
uint32_t want;
|
||||
} cases[] = {
|
||||
{ false, 1, 0 },
|
||||
{ false, 2, 1 },
|
||||
{ false, 4, 1 },
|
||||
{ true, 1, 0 },
|
||||
{ true, 2, 0 },
|
||||
{ true, 4, 0 },
|
||||
};
|
||||
unsigned i;
|
||||
int fail = 0;
|
||||
|
||||
for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++)
|
||||
{
|
||||
uint32_t got = vulkan_select_present_queue_index(
|
||||
cases[i].android, cases[i].count);
|
||||
if (got != cases[i].want)
|
||||
{
|
||||
fprintf(stderr, "FAIL: %s WSI, %u queue(s) in the family:"
|
||||
" presents on queue %u, want %u\n",
|
||||
cases[i].android ? "Android" : "non-Android",
|
||||
cases[i].count, got, cases[i].want);
|
||||
fail = 1;
|
||||
}
|
||||
}
|
||||
if (!fail)
|
||||
printf("[pass] presents stay on the graphics queue behind"
|
||||
" Android's WSI, and take a second queue elsewhere\n");
|
||||
return fail;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int skipped = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* Pure policy, ahead of the display check so it runs everywhere. */
|
||||
if (test_present_queue_policy())
|
||||
return 1;
|
||||
|
||||
if (!(s_dpy = XOpenDisplay(NULL)))
|
||||
{
|
||||
fputs("SKIP: no X display (try Xvfb; see the header"
|
||||
|
||||
Reference in new issue
Block a user