zink: handle zombie swapchains
inject a dummy, matching image that can be used until the frontend catches up and rescues us from whatever is happening Reviewed-by: Adam Jackson <ajax@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14541>
This commit is contained in:
parent
d32a897f4e
commit
ab1941fc0e
|
@ -151,7 +151,7 @@ zink_kopper_deinit_displaytarget(struct zink_screen *screen, struct kopper_displ
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct kopper_swapchain *
|
static struct kopper_swapchain *
|
||||||
kopper_CreateSwapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h)
|
kopper_CreateSwapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h, VkResult *result)
|
||||||
{
|
{
|
||||||
VkResult error = VK_SUCCESS;
|
VkResult error = VK_SUCCESS;
|
||||||
struct kopper_swapchain *cswap = CALLOC_STRUCT(kopper_swapchain);
|
struct kopper_swapchain *cswap = CALLOC_STRUCT(kopper_swapchain);
|
||||||
|
@ -227,43 +227,49 @@ kopper_CreateSwapchain(struct zink_screen *screen, struct kopper_displaytarget *
|
||||||
if (error != VK_SUCCESS) {
|
if (error != VK_SUCCESS) {
|
||||||
mesa_loge("CreateSwapchainKHR failed with %s\n", vk_Result_to_str(error));
|
mesa_loge("CreateSwapchainKHR failed with %s\n", vk_Result_to_str(error));
|
||||||
free(cswap);
|
free(cswap);
|
||||||
|
*result = error;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cswap->max_acquires = cswap->scci.minImageCount - cdt->caps.minImageCount;
|
cswap->max_acquires = cswap->scci.minImageCount - cdt->caps.minImageCount;
|
||||||
cswap->last_present = UINT32_MAX;
|
cswap->last_present = UINT32_MAX;
|
||||||
|
|
||||||
|
*result = VK_SUCCESS;
|
||||||
return cswap;
|
return cswap;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static VkResult
|
||||||
kopper_GetSwapchainImages(struct zink_screen *screen, struct kopper_swapchain *cswap)
|
kopper_GetSwapchainImages(struct zink_screen *screen, struct kopper_swapchain *cswap)
|
||||||
{
|
{
|
||||||
VkResult error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, NULL);
|
VkResult error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, NULL);
|
||||||
if (!zink_screen_handle_vkresult(screen, error))
|
zink_screen_handle_vkresult(screen, error);
|
||||||
return false;
|
if (error != VK_SUCCESS)
|
||||||
|
return error;
|
||||||
cswap->images = malloc(sizeof(VkImage) * cswap->num_images);
|
cswap->images = malloc(sizeof(VkImage) * cswap->num_images);
|
||||||
cswap->acquires = calloc(cswap->num_images, sizeof(VkSemaphore));
|
cswap->acquires = calloc(cswap->num_images, sizeof(VkSemaphore));
|
||||||
cswap->inits = calloc(cswap->num_images, sizeof(bool));
|
cswap->inits = calloc(cswap->num_images, sizeof(bool));
|
||||||
cswap->presents = _mesa_hash_table_create_u32_keys(NULL);
|
cswap->presents = _mesa_hash_table_create_u32_keys(NULL);
|
||||||
error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, cswap->images);
|
error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, cswap->images);
|
||||||
return zink_screen_handle_vkresult(screen, error);
|
zink_screen_handle_vkresult(screen, error);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static VkResult
|
||||||
update_caps(struct zink_screen *screen, struct kopper_displaytarget *cdt)
|
update_caps(struct zink_screen *screen, struct kopper_displaytarget *cdt)
|
||||||
{
|
{
|
||||||
VkResult error = VKSCR(GetPhysicalDeviceSurfaceCapabilitiesKHR)(screen->pdev, cdt->surface, &cdt->caps);
|
VkResult error = VKSCR(GetPhysicalDeviceSurfaceCapabilitiesKHR)(screen->pdev, cdt->surface, &cdt->caps);
|
||||||
return zink_screen_handle_vkresult(screen, error);
|
zink_screen_handle_vkresult(screen, error);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static VkResult
|
||||||
update_swapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h)
|
update_swapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h)
|
||||||
{
|
{
|
||||||
if (!update_caps(screen, cdt))
|
VkResult error = update_caps(screen, cdt);
|
||||||
return false;
|
if (error != VK_SUCCESS)
|
||||||
struct kopper_swapchain *cswap = kopper_CreateSwapchain(screen, cdt, w, h);
|
return error;
|
||||||
|
struct kopper_swapchain *cswap = kopper_CreateSwapchain(screen, cdt, w, h, &error);
|
||||||
if (!cswap)
|
if (!cswap)
|
||||||
return false;
|
return error;
|
||||||
destroy_swapchain(screen, cdt->old_swapchain);
|
destroy_swapchain(screen, cdt->old_swapchain);
|
||||||
cdt->old_swapchain = cdt->swapchain;
|
cdt->old_swapchain = cdt->swapchain;
|
||||||
cdt->swapchain = cswap;
|
cdt->swapchain = cswap;
|
||||||
|
@ -338,7 +344,7 @@ zink_kopper_displaytarget_create(struct zink_screen *screen, unsigned tex_usage,
|
||||||
if (!cdt->surface)
|
if (!cdt->surface)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!update_swapchain(screen, cdt, width, height))
|
if (update_swapchain(screen, cdt, width, height) != VK_SUCCESS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
simple_mtx_lock(&screen->dt_lock);
|
simple_mtx_lock(&screen->dt_lock);
|
||||||
|
@ -375,7 +381,7 @@ zink_kopper_displaytarget_destroy(struct zink_screen *screen, struct kopper_disp
|
||||||
FREE(cdt);
|
FREE(cdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static VkResult
|
||||||
kopper_acquire(struct zink_screen *screen, struct zink_resource *res, uint64_t timeout)
|
kopper_acquire(struct zink_screen *screen, struct zink_resource *res, uint64_t timeout)
|
||||||
{
|
{
|
||||||
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
|
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
|
||||||
|
@ -383,41 +389,48 @@ kopper_acquire(struct zink_screen *screen, struct zink_resource *res, uint64_t t
|
||||||
return true;
|
return true;
|
||||||
res->obj->acquire = VK_NULL_HANDLE;
|
res->obj->acquire = VK_NULL_HANDLE;
|
||||||
VkSemaphore acquire = VK_NULL_HANDLE;
|
VkSemaphore acquire = VK_NULL_HANDLE;
|
||||||
if (res->obj->new_dt) {
|
|
||||||
update_swapchain:
|
while (true) {
|
||||||
if (!update_swapchain(screen, cdt, res->base.b.width0, res->base.b.height0)) {
|
if (res->obj->new_dt) {
|
||||||
//???
|
VkResult error = update_swapchain(screen, cdt, res->base.b.width0, res->base.b.height0);
|
||||||
|
zink_screen_handle_vkresult(screen, error);
|
||||||
|
if (error != VK_SUCCESS)
|
||||||
|
return error;
|
||||||
|
res->obj->new_dt = false;
|
||||||
|
res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
res->obj->access = 0;
|
||||||
|
res->obj->access_stage = 0;
|
||||||
}
|
}
|
||||||
res->obj->new_dt = false;
|
if (timeout == UINT64_MAX && util_queue_is_initialized(&screen->flush_queue) &&
|
||||||
res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
p_atomic_read_relaxed(&cdt->swapchain->num_acquires) > cdt->swapchain->max_acquires) {
|
||||||
res->obj->access = 0;
|
util_queue_fence_wait(&res->obj->present_fence);
|
||||||
res->obj->access_stage = 0;
|
}
|
||||||
|
VkSemaphoreCreateInfo sci = {
|
||||||
|
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||||
|
NULL,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
VkResult ret;
|
||||||
|
if (!acquire) {
|
||||||
|
ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &acquire);
|
||||||
|
assert(acquire);
|
||||||
|
if (ret != VK_SUCCESS)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ASSERTED unsigned prev = res->obj->dt_idx;
|
||||||
|
ret = VKSCR(AcquireNextImageKHR)(screen->dev, cdt->swapchain->swapchain, timeout, acquire, VK_NULL_HANDLE, &res->obj->dt_idx);
|
||||||
|
if (ret != VK_SUCCESS && ret != VK_SUBOPTIMAL_KHR) {
|
||||||
|
if (ret == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
|
res->obj->new_dt = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VKSCR(DestroySemaphore)(screen->dev, acquire, NULL);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
assert(prev != res->obj->dt_idx);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (timeout == UINT64_MAX && util_queue_is_initialized(&screen->flush_queue) &&
|
|
||||||
p_atomic_read_relaxed(&cdt->swapchain->num_acquires) > cdt->swapchain->max_acquires) {
|
|
||||||
util_queue_fence_wait(&res->obj->present_fence);
|
|
||||||
}
|
|
||||||
VkSemaphoreCreateInfo sci = {
|
|
||||||
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
||||||
NULL,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
VkResult ret;
|
|
||||||
if (!acquire) {
|
|
||||||
ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &acquire);
|
|
||||||
assert(acquire);
|
|
||||||
if (ret != VK_SUCCESS)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ASSERTED unsigned prev = res->obj->dt_idx;
|
|
||||||
ret = VKSCR(AcquireNextImageKHR)(screen->dev, cdt->swapchain->swapchain, timeout, acquire, VK_NULL_HANDLE, &res->obj->dt_idx);
|
|
||||||
if (ret != VK_SUCCESS && ret != VK_SUBOPTIMAL_KHR) {
|
|
||||||
if (ret == VK_ERROR_OUT_OF_DATE_KHR)
|
|
||||||
goto update_swapchain;
|
|
||||||
VKSCR(DestroySemaphore)(screen->dev, acquire, NULL);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
assert(prev != res->obj->dt_idx);
|
|
||||||
cdt->swapchain->acquires[res->obj->dt_idx] = res->obj->acquire = acquire;
|
cdt->swapchain->acquires[res->obj->dt_idx] = res->obj->acquire = acquire;
|
||||||
res->obj->image = cdt->swapchain->images[res->obj->dt_idx];
|
res->obj->image = cdt->swapchain->images[res->obj->dt_idx];
|
||||||
res->obj->acquired = false;
|
res->obj->acquired = false;
|
||||||
|
@ -431,7 +444,28 @@ update_swapchain:
|
||||||
p_atomic_inc(&cdt->swapchain->num_acquires);
|
p_atomic_inc(&cdt->swapchain->num_acquires);
|
||||||
}
|
}
|
||||||
res->obj->dt_has_data = false;
|
res->obj->dt_has_data = false;
|
||||||
return ret == VK_SUCCESS;
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
kill_swapchain(struct zink_context *ctx, struct zink_resource *res)
|
||||||
|
{
|
||||||
|
struct zink_screen *screen = zink_screen(ctx->base.screen);
|
||||||
|
/* dead swapchain */
|
||||||
|
fprintf(stderr, "KILL %p\n", res);
|
||||||
|
zink_batch_reference_resource(&ctx->batch, res);
|
||||||
|
struct pipe_resource *pres = screen->base.resource_create(&screen->base, &res->base.b);
|
||||||
|
zink_resource_object_reference(screen, &res->obj, zink_resource(pres)->obj);
|
||||||
|
pipe_resource_reference(&pres, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_swapchain_kill(VkResult ret)
|
||||||
|
{
|
||||||
|
return ret != VK_SUCCESS &&
|
||||||
|
ret != VK_TIMEOUT &&
|
||||||
|
ret != VK_NOT_READY &&
|
||||||
|
ret != VK_SUBOPTIMAL_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -442,9 +476,13 @@ zink_kopper_acquire(struct zink_context *ctx, struct zink_resource *res, uint64_
|
||||||
const struct kopper_swapchain *cswap = cdt->swapchain;
|
const struct kopper_swapchain *cswap = cdt->swapchain;
|
||||||
res->obj->new_dt |= res->base.b.width0 != cswap->scci.imageExtent.width ||
|
res->obj->new_dt |= res->base.b.width0 != cswap->scci.imageExtent.width ||
|
||||||
res->base.b.height0 != cswap->scci.imageExtent.height;
|
res->base.b.height0 != cswap->scci.imageExtent.height;
|
||||||
bool ret = kopper_acquire(zink_screen(ctx->base.screen), res, timeout);
|
VkResult ret = kopper_acquire(zink_screen(ctx->base.screen), res, timeout);
|
||||||
if (cswap != cdt->swapchain)
|
if (ret == VK_SUCCESS || ret == VK_SUBOPTIMAL_KHR) {
|
||||||
ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
|
if (cswap != cdt->swapchain)
|
||||||
|
ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
|
||||||
|
} else if (is_swapchain_kill(ret)) {
|
||||||
|
kill_swapchain(ctx, res);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,15 +618,27 @@ zink_kopper_acquire_readback(struct zink_context *ctx, struct zink_resource *res
|
||||||
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
|
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
|
||||||
const struct kopper_swapchain *cswap = cdt->swapchain;
|
const struct kopper_swapchain *cswap = cdt->swapchain;
|
||||||
uint32_t last_dt_idx = res->obj->last_dt_idx;
|
uint32_t last_dt_idx = res->obj->last_dt_idx;
|
||||||
if (!res->obj->acquire)
|
VkResult ret = VK_SUCCESS;
|
||||||
kopper_acquire(screen, res, UINT64_MAX);
|
if (!res->obj->acquire) {
|
||||||
|
ret = kopper_acquire(screen, res, UINT64_MAX);
|
||||||
|
if (is_swapchain_kill(ret)) {
|
||||||
|
kill_swapchain(ctx, res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* if this hasn't been presented or if it has data, use this as the readback target */
|
/* if this hasn't been presented or if it has data, use this as the readback target */
|
||||||
if (res->obj->last_dt_idx == UINT32_MAX || res->obj->dt_has_data)
|
if (res->obj->last_dt_idx == UINT32_MAX || res->obj->dt_has_data)
|
||||||
return false;
|
return false;
|
||||||
while (res->obj->dt_idx != last_dt_idx) {
|
while (res->obj->dt_idx != last_dt_idx) {
|
||||||
if (!zink_kopper_present_readback(ctx, res))
|
if (!zink_kopper_present_readback(ctx, res))
|
||||||
break;
|
break;
|
||||||
while (!kopper_acquire(screen, res, 0));
|
do {
|
||||||
|
ret = kopper_acquire(screen, res, 0);
|
||||||
|
} while (!is_swapchain_kill(ret) && (ret == VK_NOT_READY || ret == VK_TIMEOUT));
|
||||||
|
if (is_swapchain_kill(ret)) {
|
||||||
|
kill_swapchain(ctx, res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (cswap != cdt->swapchain)
|
if (cswap != cdt->swapchain)
|
||||||
ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
|
ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
|
||||||
|
@ -638,7 +688,7 @@ zink_kopper_update(struct pipe_screen *pscreen, struct pipe_resource *pres, int
|
||||||
*h = res->base.b.height0;
|
*h = res->base.b.height0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!update_caps(screen, cdt)) {
|
if (update_caps(screen, cdt) != VK_SUCCESS) {
|
||||||
debug_printf("zink: failed to update swapchain capabilities");
|
debug_printf("zink: failed to update swapchain capabilities");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -455,6 +455,8 @@ zink_surface_swapchain_update(struct zink_context *ctx, struct zink_surface *sur
|
||||||
struct zink_screen *screen = zink_screen(ctx->base.screen);
|
struct zink_screen *screen = zink_screen(ctx->base.screen);
|
||||||
struct zink_resource *res = zink_resource(surface->base.texture);
|
struct zink_resource *res = zink_resource(surface->base.texture);
|
||||||
struct kopper_displaytarget *cdt = res->obj->dt;
|
struct kopper_displaytarget *cdt = res->obj->dt;
|
||||||
|
if (!cdt)
|
||||||
|
return; //dead swapchain
|
||||||
if (res->obj->dt != surface->dt) {
|
if (res->obj->dt != surface->dt) {
|
||||||
/* new swapchain: clear out previous old_swapchain and move current swapchain there */
|
/* new swapchain: clear out previous old_swapchain and move current swapchain there */
|
||||||
for (unsigned i = 0; i < surface->old_swapchain_size; i++)
|
for (unsigned i = 0; i < surface->old_swapchain_size; i++)
|
||||||
|
|
Loading…
Reference in New Issue