zink: add kopper api

Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14541>
This commit is contained in:
Mike Blumenkrantz 2022-03-22 15:05:09 -04:00 committed by Marge Bot
parent a2711e47af
commit 8ade5588e3
2 changed files with 757 additions and 0 deletions

View File

@ -0,0 +1,648 @@
/*
* Copyright 2020 Red Hat, Inc.
* Copyright © 2021 Valve Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "zink_context.h"
#include "zink_screen.h"
#include "zink_resource.h"
#include "zink_kopper.h"
#include "vk_enum_to_str.h"
#define kopper_displaytarget(dt) ((struct kopper_displaytarget*)dt)
static void
init_dt_type(struct kopper_displaytarget *cdt)
{
VkStructureType type = cdt->info.bos.sType;
switch (type) {
#ifdef VK_USE_PLATFORM_XCB_KHR
case VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR:
cdt->type = KOPPER_X11;
break;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
case VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR:
cdt->type = KOPPER_WAYLAND;
break;
#endif
default:
unreachable("unsupported!");
}
}
static VkSurfaceKHR
kopper_CreateSurface(struct zink_screen *screen, struct kopper_displaytarget *cdt)
{
VkSurfaceKHR surface = VK_NULL_HANDLE;
VkResult error = VK_SUCCESS;
init_dt_type(cdt);
VkStructureType type = cdt->info.bos.sType;
switch (type) {
#ifdef VK_USE_PLATFORM_XCB_KHR
case VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR:
error = VKSCR(CreateXcbSurfaceKHR)(screen->instance, &cdt->info.xcb, NULL, &surface);
break;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
case VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR:
error = VKSCR(CreateWaylandSurfaceKHR)(screen->instance, &cdt->info.wl, NULL, &surface);
break;
#endif
default:
unreachable("unsupported!");
}
if (error != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
VkBool32 supported;
error = VKSCR(GetPhysicalDeviceSurfaceSupportKHR)(screen->pdev, screen->gfx_queue, surface, &supported);
if (!zink_screen_handle_vkresult(screen, error) || !supported) {
VKSCR(DestroySurfaceKHR)(screen->instance, surface, NULL);
return VK_NULL_HANDLE;
}
return surface;
}
static void
destroy_swapchain(struct zink_screen *screen, struct kopper_swapchain *cswap)
{
if (!cswap)
return;
free(cswap->images);
free(cswap->inits);
for (unsigned i = 0; i < cswap->num_images; i++) {
VKSCR(DestroySemaphore)(screen->dev, cswap->acquires[i], NULL);
}
free(cswap->acquires);
hash_table_foreach(cswap->presents, he) {
struct util_dynarray *arr = he->data;
while (util_dynarray_contains(arr, VkSemaphore))
VKSCR(DestroySemaphore)(screen->dev, util_dynarray_pop(arr, VkSemaphore), NULL);
util_dynarray_fini(arr);
free(arr);
}
_mesa_hash_table_destroy(cswap->presents, NULL);
VKSCR(DestroySwapchainKHR)(screen->dev, cswap->swapchain, NULL);
free(cswap);
}
static struct hash_entry *
find_dt_entry(struct zink_screen *screen, const struct kopper_displaytarget *cdt)
{
struct hash_entry *he = NULL;
switch (cdt->type) {
#ifdef VK_USE_PLATFORM_XCB_KHR
case KOPPER_X11:
he = _mesa_hash_table_search_pre_hashed(&screen->dts, cdt->info.xcb.window, (void*)(uintptr_t)cdt->info.xcb.window);
break;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
case KOPPER_WAYLAND:
he = _mesa_hash_table_search(&screen->dts, cdt->info.wl.surface);
break;
#endif
default:
unreachable("unsupported!");
}
return he;
}
void
zink_kopper_deinit_displaytarget(struct zink_screen *screen, struct kopper_displaytarget *cdt)
{
if (!cdt->surface)
return;
simple_mtx_lock(&screen->dt_lock);
struct hash_entry *he = find_dt_entry(screen, cdt);
assert(he);
/* this deinits the registered entry, which should always be the "right" entry */
cdt = he->data;
_mesa_hash_table_remove(&screen->dts, he);
simple_mtx_unlock(&screen->dt_lock);
destroy_swapchain(screen, cdt->swapchain);
destroy_swapchain(screen, cdt->old_swapchain);
VKSCR(DestroySurfaceKHR)(screen->instance, cdt->surface, NULL);
cdt->swapchain = cdt->old_swapchain = NULL;
cdt->surface = VK_NULL_HANDLE;
}
static struct kopper_swapchain *
kopper_CreateSwapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h)
{
VkResult error = VK_SUCCESS;
struct kopper_swapchain *cswap = CALLOC_STRUCT(kopper_swapchain);
if (!cswap)
return NULL;
cswap->last_present_prune = 1;
bool has_alpha = cdt->info.has_alpha && (cdt->caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR);
if (cdt->swapchain) {
cswap->scci = cdt->swapchain->scci;
cswap->scci.oldSwapchain = cdt->swapchain->swapchain;
} else {
cswap->scci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
cswap->scci.pNext = NULL;
cswap->scci.surface = cdt->surface;
cswap->scci.flags = zink_kopper_has_srgb(cdt) ? VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR : 0;
cswap->scci.imageFormat = cdt->formats[0];
cswap->scci.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
// TODO: This is where you'd hook up stereo
cswap->scci.imageArrayLayers = 1;
cswap->scci.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
cswap->scci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
cswap->scci.queueFamilyIndexCount = 0;
cswap->scci.pQueueFamilyIndices = NULL;
cswap->scci.compositeAlpha = has_alpha ? VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
// TODO: This is where you'd hook up GLX_EXT_swap_interval and friends
cswap->scci.presentMode = cdt->type == KOPPER_X11 ? VK_PRESENT_MODE_IMMEDIATE_KHR : VK_PRESENT_MODE_FIFO_KHR;
cswap->scci.clipped = VK_TRUE;
}
cswap->scci.minImageCount = cdt->caps.minImageCount;
cswap->scci.preTransform = cdt->caps.currentTransform;
if (cdt->formats[1])
cswap->scci.pNext = &cdt->format_list;
/* different display platforms have, by vulkan spec, different sizing methodologies */
switch (cdt->type) {
case KOPPER_X11:
/* With Xcb, minImageExtent, maxImageExtent, and currentExtent must always equal the window size.
* ...
* Due to above restrictions, it is only possible to create a new swapchain on this
* platform with imageExtent being equal to the current size of the window.
*/
cswap->scci.imageExtent.width = cdt->caps.currentExtent.width;
cswap->scci.imageExtent.height = cdt->caps.currentExtent.height;
break;
case KOPPER_WAYLAND:
/* On Wayland, currentExtent is the special value (0xFFFFFFFF, 0xFFFFFFFF), indicating that the
* surface size will be determined by the extent of a swapchain targeting the surface. Whatever the
* application sets a swapchains imageExtent to will be the size of the window, after the first image is
* presented.
*/
cswap->scci.imageExtent.width = w;
cswap->scci.imageExtent.height = h;
break;
default:
unreachable("unknown display platform");
}
error = VKSCR(CreateSwapchainKHR)(screen->dev, &cswap->scci, NULL,
&cswap->swapchain);
if (error == VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) {
if (util_queue_is_initialized(&screen->flush_queue))
util_queue_finish(&screen->flush_queue);
if (VKSCR(QueueWaitIdle)(screen->queue) != VK_SUCCESS)
debug_printf("vkQueueWaitIdle failed\n");
zink_kopper_deinit_displaytarget(screen, cdt);
error = VKSCR(CreateSwapchainKHR)(screen->dev, &cswap->scci, NULL,
&cswap->swapchain);
}
if (error != VK_SUCCESS) {
mesa_loge("CreateSwapchainKHR failed with %s\n", vk_Result_to_str(error));
free(cswap);
return NULL;
}
cswap->max_acquires = cswap->scci.minImageCount - cdt->caps.minImageCount;
cswap->last_present = UINT32_MAX;
return cswap;
}
static bool
kopper_GetSwapchainImages(struct zink_screen *screen, struct kopper_swapchain *cswap)
{
VkResult error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, NULL);
if (!zink_screen_handle_vkresult(screen, error))
return false;
cswap->images = malloc(sizeof(VkImage) * cswap->num_images);
cswap->acquires = calloc(cswap->num_images, sizeof(VkSemaphore));
cswap->inits = calloc(cswap->num_images, sizeof(bool));
cswap->presents = _mesa_hash_table_create_u32_keys(NULL);
error = VKSCR(GetSwapchainImagesKHR)(screen->dev, cswap->swapchain, &cswap->num_images, cswap->images);
return zink_screen_handle_vkresult(screen, error);
}
static bool
update_caps(struct zink_screen *screen, struct kopper_displaytarget *cdt)
{
VkResult error = VKSCR(GetPhysicalDeviceSurfaceCapabilitiesKHR)(screen->pdev, cdt->surface, &cdt->caps);
return zink_screen_handle_vkresult(screen, error);
}
static bool
update_swapchain(struct zink_screen *screen, struct kopper_displaytarget *cdt, unsigned w, unsigned h)
{
if (!update_caps(screen, cdt))
return false;
struct kopper_swapchain *cswap = kopper_CreateSwapchain(screen, cdt, w, h);
if (!cswap)
return false;
destroy_swapchain(screen, cdt->old_swapchain);
cdt->old_swapchain = cdt->swapchain;
cdt->swapchain = cswap;
return kopper_GetSwapchainImages(screen, cdt->swapchain);
}
struct kopper_displaytarget *
zink_kopper_displaytarget_create(struct zink_screen *screen, unsigned tex_usage,
enum pipe_format format, unsigned width,
unsigned height, unsigned alignment,
const void *loader_private, unsigned *stride)
{
struct kopper_displaytarget *cdt;
const struct kopper_loader_info *info = loader_private;
{
struct kopper_displaytarget k;
struct hash_entry *he = NULL;
k.info = *info;
init_dt_type(&k);
simple_mtx_lock(&screen->dt_lock);
if (unlikely(!screen->dts.table)) {
switch (k.type) {
case KOPPER_X11:
_mesa_hash_table_init(&screen->dts, screen, NULL, _mesa_key_pointer_equal);
break;
case KOPPER_WAYLAND:
_mesa_hash_table_init(&screen->dts, screen, _mesa_hash_pointer, _mesa_key_pointer_equal);
break;
default:
unreachable("unknown kopper type");
}
} else {
he = find_dt_entry(screen, &k);
}
simple_mtx_unlock(&screen->dt_lock);
if (he) {
cdt = he->data;
p_atomic_inc(&cdt->refcount);
*stride = cdt->stride;
return cdt;
}
}
cdt = CALLOC_STRUCT(kopper_displaytarget);
if (!cdt)
return NULL;
cdt->refcount = 1;
cdt->loader_private = (void*)loader_private;
cdt->info = *info;
enum pipe_format srgb = PIPE_FORMAT_NONE;
if (screen->info.have_KHR_swapchain_mutable_format) {
srgb = util_format_is_srgb(format) ? util_format_linear(format) : util_format_srgb(format);
/* why do these helpers have different default return values? */
if (srgb == format)
srgb = PIPE_FORMAT_NONE;
}
cdt->formats[0] = zink_get_format(screen, format);
if (srgb) {
cdt->format_list.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO;
cdt->format_list.pNext = NULL;
cdt->format_list.viewFormatCount = 2;
cdt->format_list.pViewFormats = cdt->formats;
cdt->formats[1] = zink_get_format(screen, srgb);
}
cdt->surface = kopper_CreateSurface(screen, cdt);
if (!cdt->surface)
goto out;
if (!update_swapchain(screen, cdt, width, height))
goto out;
simple_mtx_lock(&screen->dt_lock);
switch (cdt->type) {
#ifdef VK_USE_PLATFORM_XCB_KHR
case KOPPER_X11:
_mesa_hash_table_insert_pre_hashed(&screen->dts, cdt->info.xcb.window, (void*)(uintptr_t)cdt->info.xcb.window, cdt);
break;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
case KOPPER_WAYLAND:
_mesa_hash_table_insert(&screen->dts, cdt->info.wl.surface, cdt);
break;
#endif
default:
unreachable("unsupported!");
}
simple_mtx_unlock(&screen->dt_lock);
*stride = cdt->stride;
return cdt;
//moar cleanup
out:
return NULL;
}
void
zink_kopper_displaytarget_destroy(struct zink_screen *screen, struct kopper_displaytarget *cdt)
{
if (!p_atomic_dec_zero(&cdt->refcount))
return;
zink_kopper_deinit_displaytarget(screen, cdt);
FREE(cdt);
}
static bool
kopper_acquire(struct zink_screen *screen, struct zink_resource *res, uint64_t timeout)
{
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
if (res->obj->acquire)
return true;
res->obj->acquire = VK_NULL_HANDLE;
VkSemaphore acquire = VK_NULL_HANDLE;
if (res->obj->new_dt) {
update_swapchain:
if (!update_swapchain(screen, cdt, res->base.b.width0, res->base.b.height0)) {
//???
}
res->obj->new_dt = false;
res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
res->obj->access = 0;
res->obj->access_stage = 0;
}
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;
res->obj->image = cdt->swapchain->images[res->obj->dt_idx];
res->obj->acquired = false;
if (!cdt->swapchain->inits[res->obj->dt_idx]) {
/* swapchain images are initially in the UNDEFINED layout */
res->layout = VK_IMAGE_LAYOUT_UNDEFINED;
cdt->swapchain->inits[res->obj->dt_idx] = true;
}
if (timeout == UINT64_MAX) {
res->obj->indefinite_acquire = true;
p_atomic_inc(&cdt->swapchain->num_acquires);
}
res->obj->dt_has_data = false;
return ret == VK_SUCCESS;
}
bool
zink_kopper_acquire(struct zink_context *ctx, struct zink_resource *res, uint64_t timeout)
{
assert(res->obj->dt);
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
const struct kopper_swapchain *cswap = cdt->swapchain;
res->obj->new_dt |= res->base.b.width0 != cswap->scci.imageExtent.width ||
res->base.b.height0 != cswap->scci.imageExtent.height;
bool ret = kopper_acquire(zink_screen(ctx->base.screen), res, timeout);
if (cswap != cdt->swapchain)
ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
return ret;
}
VkSemaphore
zink_kopper_acquire_submit(struct zink_screen *screen, struct zink_resource *res)
{
assert(res->obj->dt);
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
if (res->obj->acquired)
return VK_NULL_HANDLE;
assert(res->obj->acquire);
res->obj->acquired = true;
/* this is now owned by the batch */
cdt->swapchain->acquires[res->obj->dt_idx] = VK_NULL_HANDLE;
return res->obj->acquire;
}
VkSemaphore
zink_kopper_present(struct zink_screen *screen, struct zink_resource *res)
{
assert(res->obj->dt);
assert(!res->obj->present);
VkSemaphoreCreateInfo sci = {
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
NULL,
0
};
assert(res->obj->acquired);
VkResult ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &res->obj->present);
return zink_screen_handle_vkresult(screen, ret) ? res->obj->present : VK_NULL_HANDLE;
}
struct kopper_present_info {
VkPresentInfoKHR info;
uint32_t image;
struct zink_resource *res;
VkSemaphore sem;
bool indefinite_acquire;
};
static void
kopper_present(void *data, void *gdata, int thread_idx)
{
struct kopper_present_info *cpi = data;
struct kopper_displaytarget *cdt = cpi->res->obj->dt;
struct zink_screen *screen = gdata;
VkResult error;
cpi->info.pResults = &error;
simple_mtx_lock(&screen->queue_lock);
VkResult error2 = VKSCR(QueuePresentKHR)(screen->thread_queue, &cpi->info);
simple_mtx_unlock(&screen->queue_lock);
cdt->swapchain->last_present = cpi->image;
if (cpi->indefinite_acquire)
p_atomic_dec(&cdt->swapchain->num_acquires);
if (error2 == VK_SUBOPTIMAL_KHR)
cpi->res->obj->new_dt = true;
/* it's illegal to destroy semaphores if they're in use by a cmdbuf.
* but what does "in use" actually mean?
* in truth, when using timelines, nobody knows. especially not VVL.
*
* thus, to avoid infinite error spam and thread-related races,
* present semaphores need their own free queue based on the
* last-known completed timeline id so that the semaphore persists through
* normal cmdbuf submit/signal and then also exists here when it's needed for the present operation
*/
struct util_dynarray *arr;
for (; screen->last_finished && cdt->swapchain->last_present_prune != screen->last_finished; cdt->swapchain->last_present_prune++) {
struct hash_entry *he = _mesa_hash_table_search(cdt->swapchain->presents,
(void*)(uintptr_t)cdt->swapchain->last_present_prune);
if (he) {
arr = he->data;
while (util_dynarray_contains(arr, VkSemaphore))
VKSCR(DestroySemaphore)(screen->dev, util_dynarray_pop(arr, VkSemaphore), NULL);
util_dynarray_fini(arr);
free(arr);
_mesa_hash_table_remove(cdt->swapchain->presents, he);
}
}
/* queue this wait semaphore for deletion on completion of the next batch */
assert(screen->curr_batch > 0);
uint32_t next = screen->curr_batch + 1;
struct hash_entry *he = _mesa_hash_table_search(cdt->swapchain->presents, (void*)(uintptr_t)next);
if (he)
arr = he->data;
else {
arr = malloc(sizeof(struct util_dynarray));
util_dynarray_init(arr, NULL);
_mesa_hash_table_insert(cdt->swapchain->presents, (void*)(uintptr_t)next, arr);
}
util_dynarray_append(arr, VkSemaphore, cpi->sem);
free(cpi);
}
void
zink_kopper_present_queue(struct zink_screen *screen, struct zink_resource *res)
{
assert(res->obj->dt);
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
assert(res->obj->acquired);
assert(res->obj->present);
struct kopper_present_info *cpi = malloc(sizeof(struct kopper_present_info));
cpi->sem = res->obj->present;
cpi->res = res;
cpi->indefinite_acquire = res->obj->indefinite_acquire;
res->obj->last_dt_idx = cpi->image = res->obj->dt_idx;
cpi->info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
cpi->info.pNext = NULL;
cpi->info.waitSemaphoreCount = 1;
cpi->info.pWaitSemaphores = &cpi->sem;
cpi->info.swapchainCount = 1;
cpi->info.pSwapchains = &cdt->swapchain->swapchain;
cpi->info.pImageIndices = &cpi->image;
cpi->info.pResults = NULL;
res->obj->present = VK_NULL_HANDLE;
if (util_queue_is_initialized(&screen->flush_queue)) {
util_queue_add_job(&screen->flush_queue, cpi, &res->obj->present_fence,
kopper_present, NULL, 0);
} else {
kopper_present(cpi, screen, 0);
}
res->obj->acquire = VK_NULL_HANDLE;
res->obj->indefinite_acquire = res->obj->acquired = false;
res->obj->dt_idx = UINT32_MAX;
}
bool
zink_kopper_acquire_readback(struct zink_context *ctx, struct zink_resource *res)
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
assert(res->obj->dt);
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
const struct kopper_swapchain *cswap = cdt->swapchain;
uint32_t last_dt_idx = res->obj->last_dt_idx;
if (!res->obj->acquire)
kopper_acquire(screen, res, UINT64_MAX);
/* 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)
return false;
while (res->obj->dt_idx != last_dt_idx) {
if (!zink_kopper_present_readback(ctx, res))
break;
while (!kopper_acquire(screen, res, 0));
}
if (cswap != cdt->swapchain)
ctx->swapchain_size = cdt->swapchain->scci.imageExtent;
return true;
}
bool
zink_kopper_present_readback(struct zink_context *ctx, struct zink_resource *res)
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
VkSubmitInfo si = {0};
if (res->obj->last_dt_idx == UINT32_MAX)
return true;
if (res->layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
zink_resource_image_barrier(ctx, res, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
ctx->base.flush(&ctx->base, NULL, 0);
}
si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
si.signalSemaphoreCount = 1;
VkPipelineStageFlags mask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
si.pWaitDstStageMask = &mask;
VkSemaphore acquire = zink_kopper_acquire_submit(screen, res);
VkSemaphore present = zink_kopper_present(screen, res);
if (screen->threaded)
util_queue_finish(&screen->flush_queue);
si.waitSemaphoreCount = !!acquire;
si.pWaitSemaphores = &acquire;
si.pSignalSemaphores = &present;
VkResult error = VKSCR(QueueSubmit)(screen->thread_queue, 1, &si, VK_NULL_HANDLE);
if (!zink_screen_handle_vkresult(screen, error))
return false;
zink_kopper_present_queue(screen, res);
error = VKSCR(QueueWaitIdle)(screen->queue);
return zink_screen_handle_vkresult(screen, error);
}
bool
zink_kopper_update(struct pipe_screen *pscreen, struct pipe_resource *pres, int *w, int *h)
{
struct zink_resource *res = zink_resource(pres);
struct zink_screen *screen = zink_screen(pscreen);
assert(res->obj->dt);
struct kopper_displaytarget *cdt = kopper_displaytarget(res->obj->dt);
if (cdt->type != KOPPER_X11) {
*w = res->base.b.width0;
*h = res->base.b.height0;
return true;
}
if (!update_caps(screen, cdt)) {
debug_printf("zink: failed to update swapchain capabilities");
return false;
}
*w = cdt->caps.currentExtent.width;
*h = cdt->caps.currentExtent.height;
return true;
}

View File

@ -0,0 +1,109 @@
/*
* Copyright © 2021 Valve Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
*/
#ifndef ZINK_KOPPER_H
#define ZINK_KOPPER_H
#include "kopper_interface.h"
struct kopper_swapchain {
VkSwapchainKHR swapchain;
VkImage *images;
bool *inits;
unsigned last_present;
unsigned num_images;
VkSemaphore *acquires;
uint32_t last_present_prune;
struct hash_table *presents;
VkSwapchainCreateInfoKHR scci;
unsigned num_acquires;
unsigned max_acquires;
};
enum kopper_type {
KOPPER_X11,
KOPPER_WAYLAND,
};
struct kopper_displaytarget
{
unsigned refcount;
VkFormat formats[2];
unsigned width;
unsigned height;
unsigned stride;
void *loader_private;
VkSurfaceKHR surface;
struct kopper_swapchain *swapchain;
struct kopper_swapchain *old_swapchain;
struct kopper_loader_info info;
VkSurfaceCapabilitiesKHR caps;
VkImageFormatListCreateInfoKHR format_list;
enum kopper_type type;
};
struct zink_screen;
struct zink_resource;
static inline bool
zink_kopper_has_srgb(const struct kopper_displaytarget *cdt)
{
return cdt->formats[1] != VK_FORMAT_UNDEFINED;
}
static inline bool
zink_kopper_last_present_eq(const struct kopper_displaytarget *cdt, uint32_t idx)
{
return cdt->swapchain->last_present == idx;
}
struct kopper_displaytarget *
zink_kopper_displaytarget_create(struct zink_screen *screen, unsigned tex_usage,
enum pipe_format format, unsigned width,
unsigned height, unsigned alignment,
const void *loader_private, unsigned *stride);
void
zink_kopper_displaytarget_destroy(struct zink_screen *screen, struct kopper_displaytarget *cdt);
bool
zink_kopper_acquire(struct zink_context *ctx, struct zink_resource *res, uint64_t timeout);
VkSemaphore
zink_kopper_acquire_submit(struct zink_screen *screen, struct zink_resource *res);
VkSemaphore
zink_kopper_present(struct zink_screen *screen, struct zink_resource *res);
void
zink_kopper_present_queue(struct zink_screen *screen, struct zink_resource *res);
bool
zink_kopper_acquire_readback(struct zink_context *ctx, struct zink_resource *res);
bool
zink_kopper_present_readback(struct zink_context *ctx, struct zink_resource *res);
void
zink_kopper_deinit_displaytarget(struct zink_screen *screen, struct kopper_displaytarget *cdt);
#endif