mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2024-11-23 10:14:13 +08:00
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:
parent
a2711e47af
commit
8ade5588e3
648
src/gallium/drivers/zink/zink_kopper.c
Normal file
648
src/gallium/drivers/zink/zink_kopper.c
Normal 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 swapchain’s 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;
|
||||
}
|
109
src/gallium/drivers/zink/zink_kopper.h
Normal file
109
src/gallium/drivers/zink/zink_kopper.h
Normal 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
|
Loading…
Reference in New Issue
Block a user