mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-28 10:20:09 +01:00
anv: move common wsi code to x11/wayland common files.
Next task is to rename all the anv_ out of this, and move to a common location Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
This commit is contained in:
parent
e0d15fbe1d
commit
971523410f
10 changed files with 1851 additions and 1656 deletions
|
|
@ -42,15 +42,19 @@ VULKAN_FILES := \
|
|||
anv_query.c \
|
||||
anv_util.c \
|
||||
anv_wsi.c \
|
||||
anv_wsi.h \
|
||||
wsi_common.h \
|
||||
genX_pipeline_util.h \
|
||||
vk_format_info.h
|
||||
|
||||
VULKAN_WSI_WAYLAND_FILES := \
|
||||
anv_wsi_wayland.c
|
||||
anv_wsi_wayland.c \
|
||||
wsi_common_wayland.c \
|
||||
wsi_common_wayland.h
|
||||
|
||||
VULKAN_WSI_X11_FILES := \
|
||||
anv_wsi_x11.c
|
||||
anv_wsi_x11.c \
|
||||
wsi_common_x11.c \
|
||||
wsi_common_x11.h
|
||||
|
||||
VULKAN_GEM_FILES := \
|
||||
anv_gem.c
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ struct gen_l3_config;
|
|||
#include "brw_context.h"
|
||||
#include "isl/isl.h"
|
||||
|
||||
#include "wsi_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
@ -455,10 +457,6 @@ extern struct anv_dispatch_table dtable;
|
|||
|
||||
#define VK_ICD_WSI_PLATFORM_MAX 5
|
||||
|
||||
struct anv_wsi_device {
|
||||
struct anv_wsi_interface * wsi[VK_ICD_WSI_PLATFORM_MAX];
|
||||
};
|
||||
|
||||
struct anv_physical_device {
|
||||
VK_LOADER_DATA _loader_data;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@
|
|||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "anv_wsi.h"
|
||||
#include "anv_private.h"
|
||||
#include "wsi_common.h"
|
||||
#include "vk_format_info.h"
|
||||
|
||||
static const struct anv_wsi_callbacks anv_wsi_cbs = {
|
||||
|
|
|
|||
|
|
@ -24,307 +24,11 @@
|
|||
#include <wayland-client.h>
|
||||
#include <wayland-drm-client-protocol.h>
|
||||
|
||||
#include "anv_wsi.h"
|
||||
|
||||
#include "vk_format_info.h"
|
||||
#include <util/hash_table.h>
|
||||
|
||||
#define MIN_NUM_IMAGES 2
|
||||
|
||||
struct wsi_wayland;
|
||||
|
||||
struct wsi_wl_display {
|
||||
struct wl_display * display;
|
||||
struct wl_drm * drm;
|
||||
|
||||
struct wsi_wayland *wsi_wl;
|
||||
/* Vector of VkFormats supported */
|
||||
struct u_vector formats;
|
||||
|
||||
uint32_t capabilities;
|
||||
};
|
||||
|
||||
struct wsi_wayland {
|
||||
struct anv_wsi_interface base;
|
||||
|
||||
const VkAllocationCallbacks *alloc;
|
||||
VkPhysicalDevice physical_device;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
/* Hash table of wl_display -> wsi_wl_display mappings */
|
||||
struct hash_table * displays;
|
||||
|
||||
const struct anv_wsi_callbacks *cbs;
|
||||
};
|
||||
|
||||
static void
|
||||
wsi_wl_display_add_vk_format(struct wsi_wl_display *display, VkFormat format)
|
||||
{
|
||||
/* Don't add a format that's already in the list */
|
||||
VkFormat *f;
|
||||
u_vector_foreach(f, &display->formats)
|
||||
if (*f == format)
|
||||
return;
|
||||
|
||||
/* Don't add formats that aren't renderable. */
|
||||
VkFormatProperties props;
|
||||
|
||||
display->wsi_wl->cbs->get_phys_device_format_properties(display->wsi_wl->physical_device,
|
||||
format, &props);
|
||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
|
||||
return;
|
||||
|
||||
f = u_vector_add(&display->formats);
|
||||
if (f)
|
||||
*f = format;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_device(void *data, struct wl_drm *drm, const char *name)
|
||||
{
|
||||
fprintf(stderr, "wl_drm.device(%s)\n", name);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha)
|
||||
{
|
||||
switch (vk_format) {
|
||||
/* TODO: Figure out what all the formats mean and make this table
|
||||
* correct.
|
||||
*/
|
||||
#if 0
|
||||
case VK_FORMAT_R4G4B4A4_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444;
|
||||
case VK_FORMAT_R5G6B5_UNORM:
|
||||
return WL_DRM_FORMAT_BGR565;
|
||||
case VK_FORMAT_R5G5B5A1_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR1555 : WL_DRM_FORMAT_XBGR1555;
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
return WL_DRM_FORMAT_XBGR8888;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888;
|
||||
case VK_FORMAT_R10G10B10A2_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010;
|
||||
case VK_FORMAT_B4G4R4A4_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444;
|
||||
case VK_FORMAT_B5G6R5_UNORM:
|
||||
return WL_DRM_FORMAT_RGB565;
|
||||
case VK_FORMAT_B5G5R5A1_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_XRGB1555 : WL_DRM_FORMAT_XRGB1555;
|
||||
#endif
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
return WL_DRM_FORMAT_BGRX8888;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888;
|
||||
#if 0
|
||||
case VK_FORMAT_B10G10R10A2_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010;
|
||||
#endif
|
||||
|
||||
default:
|
||||
assert(!"Unsupported Vulkan format");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format)
|
||||
{
|
||||
struct wsi_wl_display *display = data;
|
||||
|
||||
switch (wl_format) {
|
||||
#if 0
|
||||
case WL_DRM_FORMAT_ABGR4444:
|
||||
case WL_DRM_FORMAT_XBGR4444:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R4G4B4A4_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_BGR565:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G6B5_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ABGR1555:
|
||||
case WL_DRM_FORMAT_XBGR1555:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G5B5A1_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_XBGR8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8_UNORM);
|
||||
/* fallthrough */
|
||||
case WL_DRM_FORMAT_ABGR8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8A8_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ABGR2101010:
|
||||
case WL_DRM_FORMAT_XBGR2101010:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R10G10B10A2_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ARGB4444:
|
||||
case WL_DRM_FORMAT_XRGB4444:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B4G4R4A4_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_RGB565:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G6R5_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ARGB1555:
|
||||
case WL_DRM_FORMAT_XRGB1555:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G5R5A1_UNORM);
|
||||
break;
|
||||
#endif
|
||||
case WL_DRM_FORMAT_XRGB8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_SRGB);
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_UNORM);
|
||||
/* fallthrough */
|
||||
case WL_DRM_FORMAT_ARGB8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_SRGB);
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_UNORM);
|
||||
break;
|
||||
#if 0
|
||||
case WL_DRM_FORMAT_ARGB2101010:
|
||||
case WL_DRM_FORMAT_XRGB2101010:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B10G10R10A2_UNORM);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_authenticated(void *data, struct wl_drm *drm)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities)
|
||||
{
|
||||
struct wsi_wl_display *display = data;
|
||||
|
||||
display->capabilities = capabilities;
|
||||
}
|
||||
|
||||
static const struct wl_drm_listener drm_listener = {
|
||||
drm_handle_device,
|
||||
drm_handle_format,
|
||||
drm_handle_authenticated,
|
||||
drm_handle_capabilities,
|
||||
};
|
||||
|
||||
static void
|
||||
registry_handle_global(void *data, struct wl_registry *registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
struct wsi_wl_display *display = data;
|
||||
|
||||
if (strcmp(interface, "wl_drm") == 0) {
|
||||
assert(display->drm == NULL);
|
||||
|
||||
assert(version >= 2);
|
||||
display->drm = wl_registry_bind(registry, name, &wl_drm_interface, 2);
|
||||
|
||||
if (display->drm)
|
||||
wl_drm_add_listener(display->drm, &drm_listener, display);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
registry_handle_global_remove(void *data, struct wl_registry *registry,
|
||||
uint32_t name)
|
||||
{ /* No-op */ }
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
registry_handle_global,
|
||||
registry_handle_global_remove
|
||||
};
|
||||
|
||||
static void
|
||||
wsi_wl_display_destroy(struct wsi_wayland *wsi, struct wsi_wl_display *display)
|
||||
{
|
||||
u_vector_finish(&display->formats);
|
||||
if (display->drm)
|
||||
wl_drm_destroy(display->drm);
|
||||
vk_free(wsi->alloc, display);
|
||||
}
|
||||
|
||||
static struct wsi_wl_display *
|
||||
wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display)
|
||||
{
|
||||
struct wsi_wl_display *display =
|
||||
vk_alloc(wsi->alloc, sizeof(*display), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!display)
|
||||
return NULL;
|
||||
|
||||
memset(display, 0, sizeof(*display));
|
||||
|
||||
display->display = wl_display;
|
||||
display->wsi_wl = wsi;
|
||||
|
||||
if (!u_vector_init(&display->formats, sizeof(VkFormat), 8))
|
||||
goto fail;
|
||||
|
||||
struct wl_registry *registry = wl_display_get_registry(wl_display);
|
||||
if (!registry)
|
||||
return NULL;
|
||||
|
||||
wl_registry_add_listener(registry, ®istry_listener, display);
|
||||
|
||||
/* Round-rip to get the wl_drm global */
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
if (!display->drm)
|
||||
goto fail;
|
||||
|
||||
/* Round-rip to get wl_drm formats and capabilities */
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
/* We need prime support */
|
||||
if (!(display->capabilities & WL_DRM_CAPABILITY_PRIME))
|
||||
goto fail;
|
||||
|
||||
/* We don't need this anymore */
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
return display;
|
||||
|
||||
fail:
|
||||
if (registry)
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
wsi_wl_display_destroy(wsi, display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct wsi_wl_display *
|
||||
wsi_wl_get_display(struct anv_wsi_device *wsi_device,
|
||||
struct wl_display *wl_display)
|
||||
{
|
||||
struct wsi_wayland *wsi =
|
||||
(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
struct hash_entry *entry = _mesa_hash_table_search(wsi->displays,
|
||||
wl_display);
|
||||
if (!entry) {
|
||||
/* We're about to make a bunch of blocking calls. Let's drop the
|
||||
* mutex for now so we don't block up too badly.
|
||||
*/
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
struct wsi_wl_display *display = wsi_wl_display_create(wsi, wl_display);
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
entry = _mesa_hash_table_search(wsi->displays, wl_display);
|
||||
if (entry) {
|
||||
/* Oops, someone raced us to it */
|
||||
wsi_wl_display_destroy(wsi, display);
|
||||
} else {
|
||||
entry = _mesa_hash_table_insert(wsi->displays, wl_display, display);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
return entry->data;
|
||||
}
|
||||
#include "anv_private.h"
|
||||
#include "wsi_common_wayland.h"
|
||||
|
||||
VkBool32 anv_GetPhysicalDeviceWaylandPresentationSupportKHR(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
|
|
@ -333,119 +37,7 @@ VkBool32 anv_GetPhysicalDeviceWaylandPresentationSupportKHR(
|
|||
{
|
||||
ANV_FROM_HANDLE(anv_physical_device, physical_device, physicalDevice);
|
||||
|
||||
return wsi_wl_get_display(&physical_device->wsi_device, display) != NULL;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_support(VkIcdSurfaceBase *surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
uint32_t queueFamilyIndex,
|
||||
VkBool32* pSupported)
|
||||
{
|
||||
*pSupported = true;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static const VkPresentModeKHR present_modes[] = {
|
||||
VK_PRESENT_MODE_MAILBOX_KHR,
|
||||
VK_PRESENT_MODE_FIFO_KHR,
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface,
|
||||
VkSurfaceCapabilitiesKHR* caps)
|
||||
{
|
||||
caps->minImageCount = MIN_NUM_IMAGES;
|
||||
caps->maxImageCount = 4;
|
||||
caps->currentExtent = (VkExtent2D) { -1, -1 };
|
||||
caps->minImageExtent = (VkExtent2D) { 1, 1 };
|
||||
caps->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
|
||||
caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->maxImageArrayLayers = 1;
|
||||
|
||||
caps->supportedCompositeAlpha =
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
|
||||
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
|
||||
|
||||
caps->supportedUsageFlags =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
uint32_t* pSurfaceFormatCount,
|
||||
VkSurfaceFormatKHR* pSurfaceFormats)
|
||||
{
|
||||
VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
|
||||
struct wsi_wl_display *display =
|
||||
wsi_wl_get_display(wsi_device, surface->display);
|
||||
|
||||
uint32_t count = u_vector_length(&display->formats);
|
||||
|
||||
if (pSurfaceFormats == NULL) {
|
||||
*pSurfaceFormatCount = count;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pSurfaceFormatCount >= count);
|
||||
*pSurfaceFormatCount = count;
|
||||
|
||||
VkFormat *f;
|
||||
u_vector_foreach(f, &display->formats) {
|
||||
*(pSurfaceFormats++) = (VkSurfaceFormatKHR) {
|
||||
.format = *f,
|
||||
/* TODO: We should get this from the compositor somehow */
|
||||
.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR,
|
||||
};
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface,
|
||||
uint32_t* pPresentModeCount,
|
||||
VkPresentModeKHR* pPresentModes)
|
||||
{
|
||||
if (pPresentModes == NULL) {
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pPresentModeCount >= ARRAY_SIZE(present_modes));
|
||||
typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult anv_create_wl_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface)
|
||||
{
|
||||
VkIcdSurfaceWayland *surface;
|
||||
|
||||
surface = vk_alloc(pAllocator, sizeof *surface, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (surface == NULL)
|
||||
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND;
|
||||
surface->display = pCreateInfo->display;
|
||||
surface->surface = pCreateInfo->surface;
|
||||
|
||||
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
|
||||
|
||||
return VK_SUCCESS;
|
||||
return wsi_wl_get_presentation_support(&physical_device->wsi_device, display);
|
||||
}
|
||||
|
||||
VkResult anv_CreateWaylandSurfaceKHR(
|
||||
|
|
@ -465,373 +57,3 @@ VkResult anv_CreateWaylandSurfaceKHR(
|
|||
|
||||
return anv_create_wl_surface(alloc, pCreateInfo, pSurface);
|
||||
}
|
||||
|
||||
struct wsi_wl_image {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
struct wl_buffer * buffer;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
struct wsi_wl_swapchain {
|
||||
struct anv_swapchain base;
|
||||
|
||||
struct wsi_wl_display * display;
|
||||
struct wl_event_queue * queue;
|
||||
struct wl_surface * surface;
|
||||
|
||||
VkExtent2D extent;
|
||||
VkFormat vk_format;
|
||||
uint32_t drm_format;
|
||||
|
||||
VkPresentModeKHR present_mode;
|
||||
bool fifo_ready;
|
||||
|
||||
uint32_t image_count;
|
||||
struct wsi_wl_image images[0];
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_get_images(struct anv_swapchain *anv_chain,
|
||||
uint32_t *pCount, VkImage *pSwapchainImages)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
if (pSwapchainImages == NULL) {
|
||||
*pCount = chain->image_count;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(chain->image_count <= *pCount);
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
pSwapchainImages[i] = chain->images[i].image;
|
||||
|
||||
*pCount = chain->image_count;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_acquire_next_image(struct anv_swapchain *anv_chain,
|
||||
uint64_t timeout,
|
||||
VkSemaphore semaphore,
|
||||
uint32_t *image_index)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
int ret = wl_display_dispatch_queue_pending(chain->display->display,
|
||||
chain->queue);
|
||||
/* XXX: I'm not sure if out-of-date is the right error here. If
|
||||
* wl_display_dispatch_queue_pending fails it most likely means we got
|
||||
* kicked by the server so this seems more-or-less correct.
|
||||
*/
|
||||
if (ret < 0)
|
||||
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
|
||||
|
||||
while (1) {
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
if (!chain->images[i].busy) {
|
||||
/* We found a non-busy image */
|
||||
*image_index = i;
|
||||
chain->images[i].busy = true;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* This time we do a blocking dispatch because we can't go
|
||||
* anywhere until we get an event.
|
||||
*/
|
||||
int ret = wl_display_roundtrip_queue(chain->display->display,
|
||||
chain->queue);
|
||||
if (ret < 0)
|
||||
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = data;
|
||||
|
||||
chain->fifo_ready = true;
|
||||
|
||||
wl_callback_destroy(callback);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {
|
||||
frame_handle_done,
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_queue_present(struct anv_swapchain *anv_chain,
|
||||
uint32_t image_index)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
|
||||
while (!chain->fifo_ready) {
|
||||
int ret = wl_display_dispatch_queue(chain->display->display,
|
||||
chain->queue);
|
||||
if (ret < 0)
|
||||
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
|
||||
}
|
||||
}
|
||||
|
||||
assert(image_index < chain->image_count);
|
||||
wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0);
|
||||
wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
|
||||
if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
|
||||
struct wl_callback *frame = wl_surface_frame(chain->surface);
|
||||
wl_proxy_set_queue((struct wl_proxy *)frame, chain->queue);
|
||||
wl_callback_add_listener(frame, &frame_listener, chain);
|
||||
chain->fifo_ready = false;
|
||||
}
|
||||
|
||||
chain->images[image_index].busy = true;
|
||||
wl_surface_commit(chain->surface);
|
||||
wl_display_flush(chain->display->display);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_handle_release(void *data, struct wl_buffer *buffer)
|
||||
{
|
||||
struct wsi_wl_image *image = data;
|
||||
|
||||
assert(image->buffer == buffer);
|
||||
|
||||
image->busy = false;
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
buffer_handle_release,
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_image_init(struct wsi_wl_swapchain *chain,
|
||||
struct wsi_wl_image *image,
|
||||
const VkSwapchainCreateInfoKHR *pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator)
|
||||
{
|
||||
VkDevice vk_device = chain->base.device;
|
||||
VkResult result;
|
||||
int fd;
|
||||
uint32_t size;
|
||||
uint32_t row_pitch;
|
||||
uint32_t offset;
|
||||
result = chain->base.image_fns->create_wsi_image(vk_device,
|
||||
pCreateInfo,
|
||||
pAllocator,
|
||||
&image->image,
|
||||
&image->memory,
|
||||
&size,
|
||||
&offset,
|
||||
&row_pitch,
|
||||
&fd);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
image->buffer = wl_drm_create_prime_buffer(chain->display->drm,
|
||||
fd, /* name */
|
||||
chain->extent.width,
|
||||
chain->extent.height,
|
||||
chain->drm_format,
|
||||
offset,
|
||||
row_pitch,
|
||||
0, 0, 0, 0 /* unused */);
|
||||
wl_display_roundtrip(chain->display->display);
|
||||
close(fd);
|
||||
|
||||
wl_proxy_set_queue((struct wl_proxy *)image->buffer, chain->queue);
|
||||
wl_buffer_add_listener(image->buffer, &buffer_listener, image);
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
chain->base.image_fns->free_wsi_image(vk_device, pAllocator,
|
||||
image->image, image->memory);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_destroy(struct anv_swapchain *anv_chain,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
if (chain->images[i].buffer)
|
||||
chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
|
||||
chain->images[i].image,
|
||||
chain->images[i].memory);
|
||||
}
|
||||
|
||||
vk_free(pAllocator, chain);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
|
||||
VkDevice device,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkSwapchainCreateInfoKHR* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
const struct anv_wsi_image_fns *image_fns,
|
||||
struct anv_swapchain **swapchain_out)
|
||||
{
|
||||
VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
|
||||
struct wsi_wl_swapchain *chain;
|
||||
VkResult result;
|
||||
|
||||
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
|
||||
|
||||
int num_images = pCreateInfo->minImageCount;
|
||||
|
||||
assert(num_images >= MIN_NUM_IMAGES);
|
||||
|
||||
/* For true mailbox mode, we need at least 4 images:
|
||||
* 1) One to scan out from
|
||||
* 2) One to have queued for scan-out
|
||||
* 3) One to be currently held by the Wayland compositor
|
||||
* 4) One to render to
|
||||
*/
|
||||
if (pCreateInfo->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
num_images = MAX2(num_images, 4);
|
||||
|
||||
size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
|
||||
chain = vk_alloc(pAllocator, size, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (chain == NULL)
|
||||
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
chain->base.device = device;
|
||||
chain->base.destroy = wsi_wl_swapchain_destroy;
|
||||
chain->base.get_images = wsi_wl_swapchain_get_images;
|
||||
chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;
|
||||
chain->base.queue_present = wsi_wl_swapchain_queue_present;
|
||||
chain->base.image_fns = image_fns;
|
||||
chain->surface = surface->surface;
|
||||
chain->extent = pCreateInfo->imageExtent;
|
||||
chain->vk_format = pCreateInfo->imageFormat;
|
||||
chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, false);
|
||||
|
||||
chain->present_mode = pCreateInfo->presentMode;
|
||||
chain->fifo_ready = true;
|
||||
|
||||
chain->image_count = num_images;
|
||||
|
||||
/* Mark a bunch of stuff as NULL. This way we can just call
|
||||
* destroy_swapchain for cleanup.
|
||||
*/
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
chain->images[i].buffer = NULL;
|
||||
chain->queue = NULL;
|
||||
|
||||
chain->display = wsi_wl_get_display(wsi_device,
|
||||
surface->display);
|
||||
if (!chain->display) {
|
||||
result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chain->queue = wl_display_create_queue(chain->display->display);
|
||||
if (!chain->queue) {
|
||||
result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
result = wsi_wl_image_init(chain, &chain->images[i],
|
||||
pCreateInfo, pAllocator);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
chain->images[i].busy = false;
|
||||
}
|
||||
|
||||
*swapchain_out = &chain->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail:
|
||||
wsi_wl_swapchain_destroy(&chain->base, pAllocator);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VkResult
|
||||
anv_wl_init_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
VkPhysicalDevice physical_device,
|
||||
const struct anv_wsi_callbacks *cbs)
|
||||
{
|
||||
struct wsi_wayland *wsi;
|
||||
VkResult result;
|
||||
|
||||
wsi = vk_alloc(alloc, sizeof(*wsi), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!wsi) {
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wsi->physical_device = physical_device;
|
||||
wsi->alloc = alloc;
|
||||
wsi->cbs = cbs;
|
||||
int ret = pthread_mutex_init(&wsi->mutex, NULL);
|
||||
if (ret != 0) {
|
||||
if (ret == ENOMEM) {
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
} else {
|
||||
/* FINISHME: Choose a better error. */
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
}
|
||||
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
wsi->displays = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
|
||||
_mesa_key_pointer_equal);
|
||||
if (!wsi->displays) {
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
goto fail_mutex;
|
||||
}
|
||||
|
||||
wsi->base.get_support = wsi_wl_surface_get_support;
|
||||
wsi->base.get_capabilities = wsi_wl_surface_get_capabilities;
|
||||
wsi->base.get_formats = wsi_wl_surface_get_formats;
|
||||
wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;
|
||||
wsi->base.create_swapchain = wsi_wl_surface_create_swapchain;
|
||||
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_mutex:
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
|
||||
fail_alloc:
|
||||
vk_free(alloc, wsi);
|
||||
fail:
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
anv_wl_finish_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc)
|
||||
{
|
||||
struct wsi_wayland *wsi =
|
||||
(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
|
||||
|
||||
if (wsi) {
|
||||
_mesa_hash_table_destroy(wsi->displays, NULL);
|
||||
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
|
||||
vk_free(alloc, wsi);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,237 +27,12 @@
|
|||
#include <xcb/dri3.h>
|
||||
#include <xcb/present.h>
|
||||
|
||||
#include "anv_wsi.h"
|
||||
#include "anv_private.h"
|
||||
#include "wsi_common_x11.h"
|
||||
|
||||
#include "vk_format_info.h"
|
||||
#include "util/hash_table.h"
|
||||
|
||||
struct wsi_x11_connection {
|
||||
bool has_dri3;
|
||||
bool has_present;
|
||||
};
|
||||
|
||||
struct wsi_x11 {
|
||||
struct anv_wsi_interface base;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
/* Hash table of xcb_connection -> wsi_x11_connection mappings */
|
||||
struct hash_table *connections;
|
||||
};
|
||||
|
||||
static struct wsi_x11_connection *
|
||||
wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
|
||||
xcb_connection_t *conn)
|
||||
{
|
||||
xcb_query_extension_cookie_t dri3_cookie, pres_cookie;
|
||||
xcb_query_extension_reply_t *dri3_reply, *pres_reply;
|
||||
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
vk_alloc(alloc, sizeof(*wsi_conn), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!wsi_conn)
|
||||
return NULL;
|
||||
|
||||
dri3_cookie = xcb_query_extension(conn, 4, "DRI3");
|
||||
pres_cookie = xcb_query_extension(conn, 7, "PRESENT");
|
||||
|
||||
dri3_reply = xcb_query_extension_reply(conn, dri3_cookie, NULL);
|
||||
pres_reply = xcb_query_extension_reply(conn, pres_cookie, NULL);
|
||||
if (dri3_reply == NULL || pres_reply == NULL) {
|
||||
free(dri3_reply);
|
||||
free(pres_reply);
|
||||
vk_free(alloc, wsi_conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wsi_conn->has_dri3 = dri3_reply->present != 0;
|
||||
wsi_conn->has_present = pres_reply->present != 0;
|
||||
|
||||
free(dri3_reply);
|
||||
free(pres_reply);
|
||||
|
||||
return wsi_conn;
|
||||
}
|
||||
|
||||
static void
|
||||
wsi_x11_connection_destroy(const VkAllocationCallbacks *alloc,
|
||||
struct wsi_x11_connection *conn)
|
||||
{
|
||||
vk_free(alloc, conn);
|
||||
}
|
||||
|
||||
static struct wsi_x11_connection *
|
||||
wsi_x11_get_connection(struct anv_wsi_device *wsi_dev,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
xcb_connection_t *conn)
|
||||
{
|
||||
struct wsi_x11 *wsi =
|
||||
(struct wsi_x11 *)wsi_dev->wsi[VK_ICD_WSI_PLATFORM_XCB];
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
struct hash_entry *entry = _mesa_hash_table_search(wsi->connections, conn);
|
||||
if (!entry) {
|
||||
/* We're about to make a bunch of blocking calls. Let's drop the
|
||||
* mutex for now so we don't block up too badly.
|
||||
*/
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
wsi_x11_connection_create(alloc, conn);
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
entry = _mesa_hash_table_search(wsi->connections, conn);
|
||||
if (entry) {
|
||||
/* Oops, someone raced us to it */
|
||||
wsi_x11_connection_destroy(alloc, wsi_conn);
|
||||
} else {
|
||||
entry = _mesa_hash_table_insert(wsi->connections, conn, wsi_conn);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
return entry->data;
|
||||
}
|
||||
|
||||
static const VkSurfaceFormatKHR formats[] = {
|
||||
{ .format = VK_FORMAT_B8G8R8A8_SRGB, },
|
||||
{ .format = VK_FORMAT_B8G8R8A8_UNORM, },
|
||||
};
|
||||
|
||||
static const VkPresentModeKHR present_modes[] = {
|
||||
VK_PRESENT_MODE_MAILBOX_KHR,
|
||||
};
|
||||
|
||||
static xcb_screen_t *
|
||||
get_screen_for_root(xcb_connection_t *conn, xcb_window_t root)
|
||||
{
|
||||
xcb_screen_iterator_t screen_iter =
|
||||
xcb_setup_roots_iterator(xcb_get_setup(conn));
|
||||
|
||||
for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
|
||||
if (screen_iter.data->root == root)
|
||||
return screen_iter.data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xcb_visualtype_t *
|
||||
screen_get_visualtype(xcb_screen_t *screen, xcb_visualid_t visual_id,
|
||||
unsigned *depth)
|
||||
{
|
||||
xcb_depth_iterator_t depth_iter =
|
||||
xcb_screen_allowed_depths_iterator(screen);
|
||||
|
||||
for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
|
||||
xcb_visualtype_iterator_t visual_iter =
|
||||
xcb_depth_visuals_iterator (depth_iter.data);
|
||||
|
||||
for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
|
||||
if (visual_iter.data->visual_id == visual_id) {
|
||||
if (depth)
|
||||
*depth = depth_iter.data->depth;
|
||||
return visual_iter.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xcb_visualtype_t *
|
||||
connection_get_visualtype(xcb_connection_t *conn, xcb_visualid_t visual_id,
|
||||
unsigned *depth)
|
||||
{
|
||||
xcb_screen_iterator_t screen_iter =
|
||||
xcb_setup_roots_iterator(xcb_get_setup(conn));
|
||||
|
||||
/* For this we have to iterate over all of the screens which is rather
|
||||
* annoying. Fortunately, there is probably only 1.
|
||||
*/
|
||||
for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
|
||||
xcb_visualtype_t *visual = screen_get_visualtype(screen_iter.data,
|
||||
visual_id, depth);
|
||||
if (visual)
|
||||
return visual;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xcb_visualtype_t *
|
||||
get_visualtype_for_window(xcb_connection_t *conn, xcb_window_t window,
|
||||
unsigned *depth)
|
||||
{
|
||||
xcb_query_tree_cookie_t tree_cookie;
|
||||
xcb_get_window_attributes_cookie_t attrib_cookie;
|
||||
xcb_query_tree_reply_t *tree;
|
||||
xcb_get_window_attributes_reply_t *attrib;
|
||||
|
||||
tree_cookie = xcb_query_tree(conn, window);
|
||||
attrib_cookie = xcb_get_window_attributes(conn, window);
|
||||
|
||||
tree = xcb_query_tree_reply(conn, tree_cookie, NULL);
|
||||
attrib = xcb_get_window_attributes_reply(conn, attrib_cookie, NULL);
|
||||
if (attrib == NULL || tree == NULL) {
|
||||
free(attrib);
|
||||
free(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xcb_window_t root = tree->root;
|
||||
xcb_visualid_t visual_id = attrib->visual;
|
||||
free(attrib);
|
||||
free(tree);
|
||||
|
||||
xcb_screen_t *screen = get_screen_for_root(conn, root);
|
||||
if (screen == NULL)
|
||||
return NULL;
|
||||
|
||||
return screen_get_visualtype(screen, visual_id, depth);
|
||||
}
|
||||
|
||||
static bool
|
||||
visual_has_alpha(xcb_visualtype_t *visual, unsigned depth)
|
||||
{
|
||||
uint32_t rgb_mask = visual->red_mask |
|
||||
visual->green_mask |
|
||||
visual->blue_mask;
|
||||
|
||||
uint32_t all_mask = 0xffffffff >> (32 - depth);
|
||||
|
||||
/* Do we have bits left over after RGB? */
|
||||
return (all_mask & ~rgb_mask) != 0;
|
||||
}
|
||||
|
||||
static VkBool32 anv_get_physical_device_xcb_presentation_support(
|
||||
struct anv_wsi_device *wsi_device,
|
||||
VkAllocationCallbacks *alloc,
|
||||
uint32_t queueFamilyIndex,
|
||||
xcb_connection_t* connection,
|
||||
xcb_visualid_t visual_id)
|
||||
{
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
wsi_x11_get_connection(wsi_device, alloc, connection);
|
||||
|
||||
if (!wsi_conn->has_dri3) {
|
||||
fprintf(stderr, "vulkan: No DRI3 support\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned visual_depth;
|
||||
if (!connection_get_visualtype(connection, visual_id, &visual_depth))
|
||||
return false;
|
||||
|
||||
if (visual_depth != 24 && visual_depth != 32)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
VkBool32 anv_GetPhysicalDeviceXcbPresentationSupportKHR(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
uint32_t queueFamilyIndex,
|
||||
|
|
@ -286,173 +61,6 @@ VkBool32 anv_GetPhysicalDeviceXlibPresentationSupportKHR(
|
|||
queueFamilyIndex, XGetXCBConnection(dpy), visualID);
|
||||
}
|
||||
|
||||
static xcb_connection_t*
|
||||
x11_surface_get_connection(VkIcdSurfaceBase *icd_surface)
|
||||
{
|
||||
if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
|
||||
return XGetXCBConnection(((VkIcdSurfaceXlib *)icd_surface)->dpy);
|
||||
else
|
||||
return ((VkIcdSurfaceXcb *)icd_surface)->connection;
|
||||
}
|
||||
|
||||
static xcb_window_t
|
||||
x11_surface_get_window(VkIcdSurfaceBase *icd_surface)
|
||||
{
|
||||
if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
|
||||
return ((VkIcdSurfaceXlib *)icd_surface)->window;
|
||||
else
|
||||
return ((VkIcdSurfaceXcb *)icd_surface)->window;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_support(VkIcdSurfaceBase *icd_surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
uint32_t queueFamilyIndex,
|
||||
VkBool32* pSupported)
|
||||
{
|
||||
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
|
||||
xcb_window_t window = x11_surface_get_window(icd_surface);
|
||||
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
wsi_x11_get_connection(wsi_device, alloc, conn);
|
||||
if (!wsi_conn)
|
||||
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
if (!wsi_conn->has_dri3) {
|
||||
fprintf(stderr, "vulkan: No DRI3 support\n");
|
||||
*pSupported = false;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
unsigned visual_depth;
|
||||
if (!get_visualtype_for_window(conn, window, &visual_depth)) {
|
||||
*pSupported = false;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
if (visual_depth != 24 && visual_depth != 32) {
|
||||
*pSupported = false;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
*pSupported = true;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_capabilities(VkIcdSurfaceBase *icd_surface,
|
||||
VkSurfaceCapabilitiesKHR *caps)
|
||||
{
|
||||
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
|
||||
xcb_window_t window = x11_surface_get_window(icd_surface);
|
||||
xcb_get_geometry_cookie_t geom_cookie;
|
||||
xcb_generic_error_t *err;
|
||||
xcb_get_geometry_reply_t *geom;
|
||||
unsigned visual_depth;
|
||||
|
||||
geom_cookie = xcb_get_geometry(conn, window);
|
||||
|
||||
/* This does a round-trip. This is why we do get_geometry first and
|
||||
* wait to read the reply until after we have a visual.
|
||||
*/
|
||||
xcb_visualtype_t *visual =
|
||||
get_visualtype_for_window(conn, window, &visual_depth);
|
||||
|
||||
geom = xcb_get_geometry_reply(conn, geom_cookie, &err);
|
||||
if (geom) {
|
||||
VkExtent2D extent = { geom->width, geom->height };
|
||||
caps->currentExtent = extent;
|
||||
caps->minImageExtent = extent;
|
||||
caps->maxImageExtent = extent;
|
||||
} else {
|
||||
/* This can happen if the client didn't wait for the configure event
|
||||
* to come back from the compositor. In that case, we don't know the
|
||||
* size of the window so we just return valid "I don't know" stuff.
|
||||
*/
|
||||
caps->currentExtent = (VkExtent2D) { -1, -1 };
|
||||
caps->minImageExtent = (VkExtent2D) { 1, 1 };
|
||||
caps->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
|
||||
}
|
||||
free(err);
|
||||
free(geom);
|
||||
|
||||
if (visual_has_alpha(visual, visual_depth)) {
|
||||
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
|
||||
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
|
||||
} else {
|
||||
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
}
|
||||
|
||||
caps->minImageCount = 2;
|
||||
caps->maxImageCount = 4;
|
||||
caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->maxImageArrayLayers = 1;
|
||||
caps->supportedUsageFlags =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_formats(VkIcdSurfaceBase *surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
uint32_t *pSurfaceFormatCount,
|
||||
VkSurfaceFormatKHR *pSurfaceFormats)
|
||||
{
|
||||
if (pSurfaceFormats == NULL) {
|
||||
*pSurfaceFormatCount = ARRAY_SIZE(formats);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pSurfaceFormatCount >= ARRAY_SIZE(formats));
|
||||
typed_memcpy(pSurfaceFormats, formats, *pSurfaceFormatCount);
|
||||
*pSurfaceFormatCount = ARRAY_SIZE(formats);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_present_modes(VkIcdSurfaceBase *surface,
|
||||
uint32_t *pPresentModeCount,
|
||||
VkPresentModeKHR *pPresentModes)
|
||||
{
|
||||
if (pPresentModes == NULL) {
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pPresentModeCount >= ARRAY_SIZE(present_modes));
|
||||
typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult anv_create_xcb_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface)
|
||||
{
|
||||
VkIcdSurfaceXcb *surface;
|
||||
|
||||
surface = vk_alloc(pAllocator, sizeof *surface, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (surface == NULL)
|
||||
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
surface->base.platform = VK_ICD_WSI_PLATFORM_XCB;
|
||||
surface->connection = pCreateInfo->connection;
|
||||
surface->window = pCreateInfo->window;
|
||||
|
||||
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult anv_CreateXcbSurfaceKHR(
|
||||
VkInstance _instance,
|
||||
const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
|
||||
|
|
@ -471,25 +79,6 @@ VkResult anv_CreateXcbSurfaceKHR(
|
|||
return anv_create_xcb_surface(alloc, pCreateInfo, pSurface);
|
||||
}
|
||||
|
||||
static VkResult anv_create_xlib_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface)
|
||||
{
|
||||
VkIcdSurfaceXlib *surface;
|
||||
|
||||
surface = vk_alloc(pAllocator, sizeof *surface, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (surface == NULL)
|
||||
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
surface->base.platform = VK_ICD_WSI_PLATFORM_XLIB;
|
||||
surface->dpy = pCreateInfo->dpy;
|
||||
surface->window = pCreateInfo->window;
|
||||
|
||||
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult anv_CreateXlibSurfaceKHR(
|
||||
VkInstance _instance,
|
||||
const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
|
||||
|
|
@ -508,432 +97,3 @@ VkResult anv_CreateXlibSurfaceKHR(
|
|||
|
||||
return anv_create_xlib_surface(alloc, pCreateInfo, pSurface);
|
||||
}
|
||||
|
||||
struct x11_image {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
xcb_pixmap_t pixmap;
|
||||
bool busy;
|
||||
struct xshmfence * shm_fence;
|
||||
uint32_t sync_fence;
|
||||
};
|
||||
|
||||
struct x11_swapchain {
|
||||
struct anv_swapchain base;
|
||||
|
||||
xcb_connection_t * conn;
|
||||
xcb_window_t window;
|
||||
xcb_gc_t gc;
|
||||
VkExtent2D extent;
|
||||
uint32_t image_count;
|
||||
|
||||
xcb_present_event_t event_id;
|
||||
xcb_special_event_t * special_event;
|
||||
uint64_t send_sbc;
|
||||
uint32_t stamp;
|
||||
|
||||
struct x11_image images[0];
|
||||
};
|
||||
|
||||
static VkResult
|
||||
x11_get_images(struct anv_swapchain *anv_chain,
|
||||
uint32_t* pCount, VkImage *pSwapchainImages)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
|
||||
if (pSwapchainImages == NULL) {
|
||||
*pCount = chain->image_count;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(chain->image_count <= *pCount);
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
pSwapchainImages[i] = chain->images[i].image;
|
||||
|
||||
*pCount = chain->image_count;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_handle_dri3_present_event(struct x11_swapchain *chain,
|
||||
xcb_present_generic_event_t *event)
|
||||
{
|
||||
switch (event->evtype) {
|
||||
case XCB_PRESENT_CONFIGURE_NOTIFY: {
|
||||
xcb_present_configure_notify_event_t *config = (void *) event;
|
||||
|
||||
if (config->width != chain->extent.width ||
|
||||
config->height != chain->extent.height)
|
||||
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
|
||||
xcb_present_idle_notify_event_t *idle = (void *) event;
|
||||
|
||||
for (unsigned i = 0; i < chain->image_count; i++) {
|
||||
if (chain->images[i].pixmap == idle->pixmap) {
|
||||
chain->images[i].busy = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XCB_PRESENT_COMPLETE_NOTIFY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_acquire_next_image(struct anv_swapchain *anv_chain,
|
||||
uint64_t timeout,
|
||||
VkSemaphore semaphore,
|
||||
uint32_t *image_index)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
|
||||
while (1) {
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
if (!chain->images[i].busy) {
|
||||
/* We found a non-busy image */
|
||||
xshmfence_await(chain->images[i].shm_fence);
|
||||
*image_index = i;
|
||||
chain->images[i].busy = true;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
xcb_flush(chain->conn);
|
||||
xcb_generic_event_t *event =
|
||||
xcb_wait_for_special_event(chain->conn, chain->special_event);
|
||||
if (!event)
|
||||
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
|
||||
|
||||
VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
|
||||
free(event);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_queue_present(struct anv_swapchain *anv_chain,
|
||||
uint32_t image_index)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
struct x11_image *image = &chain->images[image_index];
|
||||
|
||||
assert(image_index < chain->image_count);
|
||||
|
||||
uint32_t options = XCB_PRESENT_OPTION_NONE;
|
||||
|
||||
int64_t target_msc = 0;
|
||||
int64_t divisor = 0;
|
||||
int64_t remainder = 0;
|
||||
|
||||
options |= XCB_PRESENT_OPTION_ASYNC;
|
||||
|
||||
xshmfence_reset(image->shm_fence);
|
||||
|
||||
++chain->send_sbc;
|
||||
xcb_void_cookie_t cookie =
|
||||
xcb_present_pixmap(chain->conn,
|
||||
chain->window,
|
||||
image->pixmap,
|
||||
(uint32_t) chain->send_sbc,
|
||||
0, /* valid */
|
||||
0, /* update */
|
||||
0, /* x_off */
|
||||
0, /* y_off */
|
||||
XCB_NONE, /* target_crtc */
|
||||
XCB_NONE,
|
||||
image->sync_fence,
|
||||
options,
|
||||
target_msc,
|
||||
divisor,
|
||||
remainder, 0, NULL);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
image->busy = true;
|
||||
|
||||
xcb_flush(chain->conn);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
|
||||
const VkSwapchainCreateInfoKHR *pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
struct x11_image *image)
|
||||
{
|
||||
xcb_void_cookie_t cookie;
|
||||
VkResult result;
|
||||
uint32_t row_pitch;
|
||||
uint32_t offset;
|
||||
uint32_t bpp = 32;
|
||||
uint32_t depth = 24;
|
||||
int fd;
|
||||
uint32_t size;
|
||||
|
||||
result = chain->base.image_fns->create_wsi_image(device_h,
|
||||
pCreateInfo,
|
||||
pAllocator,
|
||||
&image->image,
|
||||
&image->memory,
|
||||
&size,
|
||||
&offset,
|
||||
&row_pitch,
|
||||
&fd);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
image->pixmap = xcb_generate_id(chain->conn);
|
||||
|
||||
cookie =
|
||||
xcb_dri3_pixmap_from_buffer_checked(chain->conn,
|
||||
image->pixmap,
|
||||
chain->window,
|
||||
size,
|
||||
pCreateInfo->imageExtent.width,
|
||||
pCreateInfo->imageExtent.height,
|
||||
row_pitch,
|
||||
depth, bpp, fd);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
int fence_fd = xshmfence_alloc_shm();
|
||||
if (fence_fd < 0)
|
||||
goto fail_pixmap;
|
||||
|
||||
image->shm_fence = xshmfence_map_shm(fence_fd);
|
||||
if (image->shm_fence == NULL)
|
||||
goto fail_shmfence_alloc;
|
||||
|
||||
image->sync_fence = xcb_generate_id(chain->conn);
|
||||
xcb_dri3_fence_from_fd(chain->conn,
|
||||
image->pixmap,
|
||||
image->sync_fence,
|
||||
false,
|
||||
fence_fd);
|
||||
|
||||
image->busy = false;
|
||||
xshmfence_trigger(image->shm_fence);
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_shmfence_alloc:
|
||||
close(fence_fd);
|
||||
|
||||
fail_pixmap:
|
||||
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
chain->base.image_fns->free_wsi_image(device_h, pAllocator,
|
||||
image->image, image->memory);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
x11_image_finish(struct x11_swapchain *chain,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
struct x11_image *image)
|
||||
{
|
||||
xcb_void_cookie_t cookie;
|
||||
|
||||
cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
xshmfence_unmap_shm(image->shm_fence);
|
||||
|
||||
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
|
||||
image->image, image->memory);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_swapchain_destroy(struct anv_swapchain *anv_chain,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
x11_image_finish(chain, pAllocator, &chain->images[i]);
|
||||
|
||||
xcb_unregister_for_special_event(chain->conn, chain->special_event);
|
||||
|
||||
vk_free(pAllocator, chain);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
|
||||
VkDevice device,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkSwapchainCreateInfoKHR *pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
const struct anv_wsi_image_fns *image_fns,
|
||||
struct anv_swapchain **swapchain_out)
|
||||
{
|
||||
struct x11_swapchain *chain;
|
||||
xcb_void_cookie_t cookie;
|
||||
VkResult result;
|
||||
|
||||
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
|
||||
|
||||
int num_images = pCreateInfo->minImageCount;
|
||||
|
||||
/* For true mailbox mode, we need at least 4 images:
|
||||
* 1) One to scan out from
|
||||
* 2) One to have queued for scan-out
|
||||
* 3) One to be currently held by the Wayland compositor
|
||||
* 4) One to render to
|
||||
*/
|
||||
if (pCreateInfo->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
num_images = MAX2(num_images, 4);
|
||||
|
||||
size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
|
||||
chain = vk_alloc(pAllocator, size, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (chain == NULL)
|
||||
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
chain->base.device = device;
|
||||
chain->base.destroy = x11_swapchain_destroy;
|
||||
chain->base.get_images = x11_get_images;
|
||||
chain->base.acquire_next_image = x11_acquire_next_image;
|
||||
chain->base.queue_present = x11_queue_present;
|
||||
chain->base.image_fns = image_fns;
|
||||
chain->conn = x11_surface_get_connection(icd_surface);
|
||||
chain->window = x11_surface_get_window(icd_surface);
|
||||
chain->extent = pCreateInfo->imageExtent;
|
||||
chain->image_count = num_images;
|
||||
chain->send_sbc = 0;
|
||||
|
||||
chain->event_id = xcb_generate_id(chain->conn);
|
||||
xcb_present_select_input(chain->conn, chain->event_id, chain->window,
|
||||
XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
|
||||
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
|
||||
XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
|
||||
|
||||
/* Create an XCB event queue to hold present events outside of the usual
|
||||
* application event queue
|
||||
*/
|
||||
chain->special_event =
|
||||
xcb_register_for_special_xge(chain->conn, &xcb_present_id,
|
||||
chain->event_id, NULL);
|
||||
|
||||
chain->gc = xcb_generate_id(chain->conn);
|
||||
if (!chain->gc) {
|
||||
/* FINISHME: Choose a better error. */
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
goto fail_register;
|
||||
}
|
||||
|
||||
cookie = xcb_create_gc(chain->conn,
|
||||
chain->gc,
|
||||
chain->window,
|
||||
XCB_GC_GRAPHICS_EXPOSURES,
|
||||
(uint32_t []) { 0 });
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
uint32_t image = 0;
|
||||
for (; image < chain->image_count; image++) {
|
||||
result = x11_image_init(device, chain, pCreateInfo, pAllocator,
|
||||
&chain->images[image]);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_init_images;
|
||||
}
|
||||
|
||||
*swapchain_out = &chain->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_init_images:
|
||||
for (uint32_t j = 0; j < image; j++)
|
||||
x11_image_finish(chain, pAllocator, &chain->images[j]);
|
||||
|
||||
fail_register:
|
||||
xcb_unregister_for_special_event(chain->conn, chain->special_event);
|
||||
|
||||
vk_free(pAllocator, chain);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VkResult
|
||||
anv_x11_init_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc)
|
||||
{
|
||||
struct wsi_x11 *wsi;
|
||||
VkResult result;
|
||||
|
||||
wsi = vk_alloc(alloc, sizeof(*wsi), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!wsi) {
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int ret = pthread_mutex_init(&wsi->mutex, NULL);
|
||||
if (ret != 0) {
|
||||
if (ret == ENOMEM) {
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
} else {
|
||||
/* FINISHME: Choose a better error. */
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
}
|
||||
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
wsi->connections = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
|
||||
_mesa_key_pointer_equal);
|
||||
if (!wsi->connections) {
|
||||
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
goto fail_mutex;
|
||||
}
|
||||
|
||||
wsi->base.get_support = x11_surface_get_support;
|
||||
wsi->base.get_capabilities = x11_surface_get_capabilities;
|
||||
wsi->base.get_formats = x11_surface_get_formats;
|
||||
wsi->base.get_present_modes = x11_surface_get_present_modes;
|
||||
wsi->base.create_swapchain = x11_surface_create_swapchain;
|
||||
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = &wsi->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_mutex:
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
fail_alloc:
|
||||
vk_free(alloc, wsi);
|
||||
fail:
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = NULL;
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
anv_x11_finish_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc)
|
||||
{
|
||||
struct wsi_x11 *wsi =
|
||||
(struct wsi_x11 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB];
|
||||
|
||||
if (wsi) {
|
||||
_mesa_hash_table_destroy(wsi->connections, NULL);
|
||||
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
|
||||
vk_free(alloc, wsi);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,17 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef WSI_COMMON_H
|
||||
#define WSI_COMMON_H
|
||||
|
||||
#ifndef ANV_WSI_H
|
||||
#define ANV_WSI_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "anv_private.h"
|
||||
|
||||
struct anv_swapchain;
|
||||
#include "util/vk_alloc.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vk_icd.h>
|
||||
|
||||
struct anv_wsi_device;
|
||||
struct anv_wsi_image_fns {
|
||||
VkResult (*create_wsi_image)(VkDevice device_h,
|
||||
const VkSwapchainCreateInfoKHR *pCreateInfo,
|
||||
|
|
@ -44,6 +47,24 @@ struct anv_wsi_image_fns {
|
|||
VkDeviceMemory memory_h);
|
||||
};
|
||||
|
||||
struct anv_swapchain {
|
||||
|
||||
VkDevice device;
|
||||
VkAllocationCallbacks alloc;
|
||||
const struct anv_wsi_image_fns *image_fns;
|
||||
VkFence fences[3];
|
||||
|
||||
VkResult (*destroy)(struct anv_swapchain *swapchain,
|
||||
const VkAllocationCallbacks *pAllocator);
|
||||
VkResult (*get_images)(struct anv_swapchain *swapchain,
|
||||
uint32_t *pCount, VkImage *pSwapchainImages);
|
||||
VkResult (*acquire_next_image)(struct anv_swapchain *swap_chain,
|
||||
uint64_t timeout, VkSemaphore semaphore,
|
||||
uint32_t *image_index);
|
||||
VkResult (*queue_present)(struct anv_swapchain *swap_chain,
|
||||
uint32_t image_index);
|
||||
};
|
||||
|
||||
struct anv_wsi_interface {
|
||||
VkResult (*get_support)(VkIcdSurfaceBase *surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
|
|
@ -68,42 +89,43 @@ struct anv_wsi_interface {
|
|||
struct anv_swapchain **swapchain);
|
||||
};
|
||||
|
||||
struct anv_swapchain {
|
||||
#define VK_ICD_WSI_PLATFORM_MAX 5
|
||||
|
||||
VkDevice device;
|
||||
VkAllocationCallbacks alloc;
|
||||
const struct anv_wsi_image_fns *image_fns;
|
||||
VkFence fences[3];
|
||||
|
||||
VkResult (*destroy)(struct anv_swapchain *swapchain,
|
||||
const VkAllocationCallbacks *pAllocator);
|
||||
VkResult (*get_images)(struct anv_swapchain *swapchain,
|
||||
uint32_t *pCount, VkImage *pSwapchainImages);
|
||||
VkResult (*acquire_next_image)(struct anv_swapchain *swap_chain,
|
||||
uint64_t timeout, VkSemaphore semaphore,
|
||||
uint32_t *image_index);
|
||||
VkResult (*queue_present)(struct anv_swapchain *swap_chain,
|
||||
uint32_t image_index);
|
||||
struct anv_wsi_device {
|
||||
struct anv_wsi_interface * wsi[VK_ICD_WSI_PLATFORM_MAX];
|
||||
};
|
||||
|
||||
ANV_DEFINE_NONDISP_HANDLE_CASTS(_VkIcdSurfaceBase, VkSurfaceKHR)
|
||||
ANV_DEFINE_NONDISP_HANDLE_CASTS(anv_swapchain, VkSwapchainKHR)
|
||||
|
||||
struct anv_wsi_callbacks {
|
||||
void (*get_phys_device_format_properties)(VkPhysicalDevice physicalDevice,
|
||||
VkFormat format,
|
||||
VkFormatProperties *pFormatProperties);
|
||||
};
|
||||
|
||||
#define WSI_DEFINE_NONDISP_HANDLE_CASTS(__wsi_type, __VkType) \
|
||||
\
|
||||
static inline struct __wsi_type * \
|
||||
__wsi_type ## _from_handle(__VkType _handle) \
|
||||
{ \
|
||||
return (struct __wsi_type *)(uintptr_t) _handle; \
|
||||
} \
|
||||
\
|
||||
static inline __VkType \
|
||||
__wsi_type ## _to_handle(struct __wsi_type *_obj) \
|
||||
{ \
|
||||
return (__VkType)(uintptr_t) _obj; \
|
||||
}
|
||||
|
||||
WSI_DEFINE_NONDISP_HANDLE_CASTS(_VkIcdSurfaceBase, VkSurfaceKHR)
|
||||
WSI_DEFINE_NONDISP_HANDLE_CASTS(anv_swapchain, VkSwapchainKHR)
|
||||
VkResult anv_x11_init_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc);
|
||||
void anv_x11_finish_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc);
|
||||
|
||||
VkResult anv_wl_init_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
VkPhysicalDevice physical_device,
|
||||
const struct anv_wsi_callbacks *cbs);
|
||||
void anv_wl_finish_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc);
|
||||
#endif /* ANV_WSI_H */
|
||||
|
||||
#endif
|
||||
827
src/intel/vulkan/wsi_common_wayland.c
Normal file
827
src/intel/vulkan/wsi_common_wayland.c
Normal file
|
|
@ -0,0 +1,827 @@
|
|||
/*
|
||||
* Copyright © 2015 Intel 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 <wayland-client.h>
|
||||
#include <wayland-drm-client-protocol.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wsi_common_wayland.h"
|
||||
#include "vk_format_info.h"
|
||||
#include <util/hash_table.h>
|
||||
#include <util/u_vector.h>
|
||||
|
||||
#define typed_memcpy(dest, src, count) ({ \
|
||||
static_assert(sizeof(*src) == sizeof(*dest), ""); \
|
||||
memcpy((dest), (src), (count) * sizeof(*(src))); \
|
||||
})
|
||||
|
||||
#define MIN_NUM_IMAGES 2
|
||||
|
||||
struct wsi_wayland;
|
||||
|
||||
struct wsi_wl_display {
|
||||
struct wl_display * display;
|
||||
struct wl_drm * drm;
|
||||
|
||||
struct wsi_wayland *wsi_wl;
|
||||
/* Vector of VkFormats supported */
|
||||
struct u_vector formats;
|
||||
|
||||
uint32_t capabilities;
|
||||
};
|
||||
|
||||
struct wsi_wayland {
|
||||
struct anv_wsi_interface base;
|
||||
|
||||
const VkAllocationCallbacks *alloc;
|
||||
VkPhysicalDevice physical_device;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
/* Hash table of wl_display -> wsi_wl_display mappings */
|
||||
struct hash_table * displays;
|
||||
|
||||
const struct anv_wsi_callbacks *cbs;
|
||||
};
|
||||
|
||||
static void
|
||||
wsi_wl_display_add_vk_format(struct wsi_wl_display *display, VkFormat format)
|
||||
{
|
||||
/* Don't add a format that's already in the list */
|
||||
VkFormat *f;
|
||||
u_vector_foreach(f, &display->formats)
|
||||
if (*f == format)
|
||||
return;
|
||||
|
||||
/* Don't add formats that aren't renderable. */
|
||||
VkFormatProperties props;
|
||||
|
||||
display->wsi_wl->cbs->get_phys_device_format_properties(display->wsi_wl->physical_device,
|
||||
format, &props);
|
||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
|
||||
return;
|
||||
|
||||
f = u_vector_add(&display->formats);
|
||||
if (f)
|
||||
*f = format;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_device(void *data, struct wl_drm *drm, const char *name)
|
||||
{
|
||||
fprintf(stderr, "wl_drm.device(%s)\n", name);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha)
|
||||
{
|
||||
switch (vk_format) {
|
||||
/* TODO: Figure out what all the formats mean and make this table
|
||||
* correct.
|
||||
*/
|
||||
#if 0
|
||||
case VK_FORMAT_R4G4B4A4_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444;
|
||||
case VK_FORMAT_R5G6B5_UNORM:
|
||||
return WL_DRM_FORMAT_BGR565;
|
||||
case VK_FORMAT_R5G5B5A1_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR1555 : WL_DRM_FORMAT_XBGR1555;
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
return WL_DRM_FORMAT_XBGR8888;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888;
|
||||
case VK_FORMAT_R10G10B10A2_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010;
|
||||
case VK_FORMAT_B4G4R4A4_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444;
|
||||
case VK_FORMAT_B5G6R5_UNORM:
|
||||
return WL_DRM_FORMAT_RGB565;
|
||||
case VK_FORMAT_B5G5R5A1_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_XRGB1555 : WL_DRM_FORMAT_XRGB1555;
|
||||
#endif
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
return WL_DRM_FORMAT_BGRX8888;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888;
|
||||
#if 0
|
||||
case VK_FORMAT_B10G10R10A2_UNORM:
|
||||
return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010;
|
||||
#endif
|
||||
|
||||
default:
|
||||
assert(!"Unsupported Vulkan format");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format)
|
||||
{
|
||||
struct wsi_wl_display *display = data;
|
||||
|
||||
switch (wl_format) {
|
||||
#if 0
|
||||
case WL_DRM_FORMAT_ABGR4444:
|
||||
case WL_DRM_FORMAT_XBGR4444:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R4G4B4A4_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_BGR565:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G6B5_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ABGR1555:
|
||||
case WL_DRM_FORMAT_XBGR1555:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G5B5A1_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_XBGR8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8_UNORM);
|
||||
/* fallthrough */
|
||||
case WL_DRM_FORMAT_ABGR8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8A8_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ABGR2101010:
|
||||
case WL_DRM_FORMAT_XBGR2101010:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_R10G10B10A2_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ARGB4444:
|
||||
case WL_DRM_FORMAT_XRGB4444:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B4G4R4A4_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_RGB565:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G6R5_UNORM);
|
||||
break;
|
||||
case WL_DRM_FORMAT_ARGB1555:
|
||||
case WL_DRM_FORMAT_XRGB1555:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G5R5A1_UNORM);
|
||||
break;
|
||||
#endif
|
||||
case WL_DRM_FORMAT_XRGB8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_SRGB);
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_UNORM);
|
||||
/* fallthrough */
|
||||
case WL_DRM_FORMAT_ARGB8888:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_SRGB);
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_UNORM);
|
||||
break;
|
||||
#if 0
|
||||
case WL_DRM_FORMAT_ARGB2101010:
|
||||
case WL_DRM_FORMAT_XRGB2101010:
|
||||
wsi_wl_display_add_vk_format(display, VK_FORMAT_B10G10R10A2_UNORM);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_authenticated(void *data, struct wl_drm *drm)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities)
|
||||
{
|
||||
struct wsi_wl_display *display = data;
|
||||
|
||||
display->capabilities = capabilities;
|
||||
}
|
||||
|
||||
static const struct wl_drm_listener drm_listener = {
|
||||
drm_handle_device,
|
||||
drm_handle_format,
|
||||
drm_handle_authenticated,
|
||||
drm_handle_capabilities,
|
||||
};
|
||||
|
||||
static void
|
||||
registry_handle_global(void *data, struct wl_registry *registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
struct wsi_wl_display *display = data;
|
||||
|
||||
if (strcmp(interface, "wl_drm") == 0) {
|
||||
assert(display->drm == NULL);
|
||||
|
||||
assert(version >= 2);
|
||||
display->drm = wl_registry_bind(registry, name, &wl_drm_interface, 2);
|
||||
|
||||
if (display->drm)
|
||||
wl_drm_add_listener(display->drm, &drm_listener, display);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
registry_handle_global_remove(void *data, struct wl_registry *registry,
|
||||
uint32_t name)
|
||||
{ /* No-op */ }
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
registry_handle_global,
|
||||
registry_handle_global_remove
|
||||
};
|
||||
|
||||
static void
|
||||
wsi_wl_display_destroy(struct wsi_wayland *wsi, struct wsi_wl_display *display)
|
||||
{
|
||||
u_vector_finish(&display->formats);
|
||||
if (display->drm)
|
||||
wl_drm_destroy(display->drm);
|
||||
vk_free(wsi->alloc, display);
|
||||
}
|
||||
|
||||
static struct wsi_wl_display *
|
||||
wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display)
|
||||
{
|
||||
struct wsi_wl_display *display =
|
||||
vk_alloc(wsi->alloc, sizeof(*display), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!display)
|
||||
return NULL;
|
||||
|
||||
memset(display, 0, sizeof(*display));
|
||||
|
||||
display->display = wl_display;
|
||||
display->wsi_wl = wsi;
|
||||
|
||||
if (!u_vector_init(&display->formats, sizeof(VkFormat), 8))
|
||||
goto fail;
|
||||
|
||||
struct wl_registry *registry = wl_display_get_registry(wl_display);
|
||||
if (!registry)
|
||||
return NULL;
|
||||
|
||||
wl_registry_add_listener(registry, ®istry_listener, display);
|
||||
|
||||
/* Round-rip to get the wl_drm global */
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
if (!display->drm)
|
||||
goto fail;
|
||||
|
||||
/* Round-rip to get wl_drm formats and capabilities */
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
/* We need prime support */
|
||||
if (!(display->capabilities & WL_DRM_CAPABILITY_PRIME))
|
||||
goto fail;
|
||||
|
||||
/* We don't need this anymore */
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
return display;
|
||||
|
||||
fail:
|
||||
if (registry)
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
wsi_wl_display_destroy(wsi, display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct wsi_wl_display *
|
||||
wsi_wl_get_display(struct anv_wsi_device *wsi_device,
|
||||
struct wl_display *wl_display)
|
||||
{
|
||||
struct wsi_wayland *wsi =
|
||||
(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
struct hash_entry *entry = _mesa_hash_table_search(wsi->displays,
|
||||
wl_display);
|
||||
if (!entry) {
|
||||
/* We're about to make a bunch of blocking calls. Let's drop the
|
||||
* mutex for now so we don't block up too badly.
|
||||
*/
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
struct wsi_wl_display *display = wsi_wl_display_create(wsi, wl_display);
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
entry = _mesa_hash_table_search(wsi->displays, wl_display);
|
||||
if (entry) {
|
||||
/* Oops, someone raced us to it */
|
||||
wsi_wl_display_destroy(wsi, display);
|
||||
} else {
|
||||
entry = _mesa_hash_table_insert(wsi->displays, wl_display, display);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
return entry->data;
|
||||
}
|
||||
|
||||
VkBool32
|
||||
wsi_wl_get_presentation_support(struct anv_wsi_device *wsi_device,
|
||||
struct wl_display *wl_display)
|
||||
{
|
||||
return wsi_wl_get_display(wsi_device, wl_display) != NULL;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_support(VkIcdSurfaceBase *surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
uint32_t queueFamilyIndex,
|
||||
VkBool32* pSupported)
|
||||
{
|
||||
*pSupported = true;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static const VkPresentModeKHR present_modes[] = {
|
||||
VK_PRESENT_MODE_MAILBOX_KHR,
|
||||
VK_PRESENT_MODE_FIFO_KHR,
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface,
|
||||
VkSurfaceCapabilitiesKHR* caps)
|
||||
{
|
||||
caps->minImageCount = MIN_NUM_IMAGES;
|
||||
caps->maxImageCount = 4;
|
||||
caps->currentExtent = (VkExtent2D) { -1, -1 };
|
||||
caps->minImageExtent = (VkExtent2D) { 1, 1 };
|
||||
caps->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
|
||||
caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->maxImageArrayLayers = 1;
|
||||
|
||||
caps->supportedCompositeAlpha =
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
|
||||
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
|
||||
|
||||
caps->supportedUsageFlags =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
uint32_t* pSurfaceFormatCount,
|
||||
VkSurfaceFormatKHR* pSurfaceFormats)
|
||||
{
|
||||
VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
|
||||
struct wsi_wl_display *display =
|
||||
wsi_wl_get_display(wsi_device, surface->display);
|
||||
|
||||
uint32_t count = u_vector_length(&display->formats);
|
||||
|
||||
if (pSurfaceFormats == NULL) {
|
||||
*pSurfaceFormatCount = count;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pSurfaceFormatCount >= count);
|
||||
*pSurfaceFormatCount = count;
|
||||
|
||||
VkFormat *f;
|
||||
u_vector_foreach(f, &display->formats) {
|
||||
*(pSurfaceFormats++) = (VkSurfaceFormatKHR) {
|
||||
.format = *f,
|
||||
/* TODO: We should get this from the compositor somehow */
|
||||
.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR,
|
||||
};
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface,
|
||||
uint32_t* pPresentModeCount,
|
||||
VkPresentModeKHR* pPresentModes)
|
||||
{
|
||||
if (pPresentModes == NULL) {
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pPresentModeCount >= ARRAY_SIZE(present_modes));
|
||||
typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult anv_create_wl_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface)
|
||||
{
|
||||
VkIcdSurfaceWayland *surface;
|
||||
|
||||
surface = vk_alloc(pAllocator, sizeof *surface, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (surface == NULL)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND;
|
||||
surface->display = pCreateInfo->display;
|
||||
surface->surface = pCreateInfo->surface;
|
||||
|
||||
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
struct wsi_wl_image {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
struct wl_buffer * buffer;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
struct wsi_wl_swapchain {
|
||||
struct anv_swapchain base;
|
||||
|
||||
struct wsi_wl_display * display;
|
||||
struct wl_event_queue * queue;
|
||||
struct wl_surface * surface;
|
||||
|
||||
VkExtent2D extent;
|
||||
VkFormat vk_format;
|
||||
uint32_t drm_format;
|
||||
|
||||
VkPresentModeKHR present_mode;
|
||||
bool fifo_ready;
|
||||
|
||||
uint32_t image_count;
|
||||
struct wsi_wl_image images[0];
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_get_images(struct anv_swapchain *anv_chain,
|
||||
uint32_t *pCount, VkImage *pSwapchainImages)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
if (pSwapchainImages == NULL) {
|
||||
*pCount = chain->image_count;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(chain->image_count <= *pCount);
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
pSwapchainImages[i] = chain->images[i].image;
|
||||
|
||||
*pCount = chain->image_count;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_acquire_next_image(struct anv_swapchain *anv_chain,
|
||||
uint64_t timeout,
|
||||
VkSemaphore semaphore,
|
||||
uint32_t *image_index)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
int ret = wl_display_dispatch_queue_pending(chain->display->display,
|
||||
chain->queue);
|
||||
/* XXX: I'm not sure if out-of-date is the right error here. If
|
||||
* wl_display_dispatch_queue_pending fails it most likely means we got
|
||||
* kicked by the server so this seems more-or-less correct.
|
||||
*/
|
||||
if (ret < 0)
|
||||
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||
|
||||
while (1) {
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
if (!chain->images[i].busy) {
|
||||
/* We found a non-busy image */
|
||||
*image_index = i;
|
||||
chain->images[i].busy = true;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* This time we do a blocking dispatch because we can't go
|
||||
* anywhere until we get an event.
|
||||
*/
|
||||
int ret = wl_display_roundtrip_queue(chain->display->display,
|
||||
chain->queue);
|
||||
if (ret < 0)
|
||||
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = data;
|
||||
|
||||
chain->fifo_ready = true;
|
||||
|
||||
wl_callback_destroy(callback);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {
|
||||
frame_handle_done,
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_queue_present(struct anv_swapchain *anv_chain,
|
||||
uint32_t image_index)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
|
||||
while (!chain->fifo_ready) {
|
||||
int ret = wl_display_dispatch_queue(chain->display->display,
|
||||
chain->queue);
|
||||
if (ret < 0)
|
||||
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||
}
|
||||
}
|
||||
|
||||
assert(image_index < chain->image_count);
|
||||
wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0);
|
||||
wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
|
||||
if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
|
||||
struct wl_callback *frame = wl_surface_frame(chain->surface);
|
||||
wl_proxy_set_queue((struct wl_proxy *)frame, chain->queue);
|
||||
wl_callback_add_listener(frame, &frame_listener, chain);
|
||||
chain->fifo_ready = false;
|
||||
}
|
||||
|
||||
chain->images[image_index].busy = true;
|
||||
wl_surface_commit(chain->surface);
|
||||
wl_display_flush(chain->display->display);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_handle_release(void *data, struct wl_buffer *buffer)
|
||||
{
|
||||
struct wsi_wl_image *image = data;
|
||||
|
||||
assert(image->buffer == buffer);
|
||||
|
||||
image->busy = false;
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
buffer_handle_release,
|
||||
};
|
||||
|
||||
static VkResult
|
||||
wsi_wl_image_init(struct wsi_wl_swapchain *chain,
|
||||
struct wsi_wl_image *image,
|
||||
const VkSwapchainCreateInfoKHR *pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator)
|
||||
{
|
||||
VkDevice vk_device = chain->base.device;
|
||||
VkResult result;
|
||||
int fd;
|
||||
uint32_t size;
|
||||
uint32_t row_pitch;
|
||||
uint32_t offset;
|
||||
result = chain->base.image_fns->create_wsi_image(vk_device,
|
||||
pCreateInfo,
|
||||
pAllocator,
|
||||
&image->image,
|
||||
&image->memory,
|
||||
&size,
|
||||
&offset,
|
||||
&row_pitch,
|
||||
&fd);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
image->buffer = wl_drm_create_prime_buffer(chain->display->drm,
|
||||
fd, /* name */
|
||||
chain->extent.width,
|
||||
chain->extent.height,
|
||||
chain->drm_format,
|
||||
offset,
|
||||
row_pitch,
|
||||
0, 0, 0, 0 /* unused */);
|
||||
wl_display_roundtrip(chain->display->display);
|
||||
close(fd);
|
||||
|
||||
wl_proxy_set_queue((struct wl_proxy *)image->buffer, chain->queue);
|
||||
wl_buffer_add_listener(image->buffer, &buffer_listener, image);
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
chain->base.image_fns->free_wsi_image(vk_device, pAllocator,
|
||||
image->image, image->memory);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_swapchain_destroy(struct anv_swapchain *anv_chain,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)anv_chain;
|
||||
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
if (chain->images[i].buffer)
|
||||
chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
|
||||
chain->images[i].image,
|
||||
chain->images[i].memory);
|
||||
}
|
||||
|
||||
vk_free(pAllocator, chain);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
|
||||
VkDevice device,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkSwapchainCreateInfoKHR* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
const struct anv_wsi_image_fns *image_fns,
|
||||
struct anv_swapchain **swapchain_out)
|
||||
{
|
||||
VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
|
||||
struct wsi_wl_swapchain *chain;
|
||||
VkResult result;
|
||||
|
||||
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
|
||||
|
||||
int num_images = pCreateInfo->minImageCount;
|
||||
|
||||
assert(num_images >= MIN_NUM_IMAGES);
|
||||
|
||||
/* For true mailbox mode, we need at least 4 images:
|
||||
* 1) One to scan out from
|
||||
* 2) One to have queued for scan-out
|
||||
* 3) One to be currently held by the Wayland compositor
|
||||
* 4) One to render to
|
||||
*/
|
||||
if (pCreateInfo->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
num_images = MAX2(num_images, 4);
|
||||
|
||||
size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
|
||||
chain = vk_alloc(pAllocator, size, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (chain == NULL)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
chain->base.device = device;
|
||||
chain->base.destroy = wsi_wl_swapchain_destroy;
|
||||
chain->base.get_images = wsi_wl_swapchain_get_images;
|
||||
chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;
|
||||
chain->base.queue_present = wsi_wl_swapchain_queue_present;
|
||||
chain->base.image_fns = image_fns;
|
||||
chain->surface = surface->surface;
|
||||
chain->extent = pCreateInfo->imageExtent;
|
||||
chain->vk_format = pCreateInfo->imageFormat;
|
||||
chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, false);
|
||||
|
||||
chain->present_mode = pCreateInfo->presentMode;
|
||||
chain->fifo_ready = true;
|
||||
|
||||
chain->image_count = num_images;
|
||||
|
||||
/* Mark a bunch of stuff as NULL. This way we can just call
|
||||
* destroy_swapchain for cleanup.
|
||||
*/
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
chain->images[i].buffer = NULL;
|
||||
chain->queue = NULL;
|
||||
|
||||
chain->display = wsi_wl_get_display(wsi_device,
|
||||
surface->display);
|
||||
if (!chain->display) {
|
||||
result = VK_ERROR_INITIALIZATION_FAILED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chain->queue = wl_display_create_queue(chain->display->display);
|
||||
if (!chain->queue) {
|
||||
result = VK_ERROR_INITIALIZATION_FAILED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
result = wsi_wl_image_init(chain, &chain->images[i],
|
||||
pCreateInfo, pAllocator);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
chain->images[i].busy = false;
|
||||
}
|
||||
|
||||
*swapchain_out = &chain->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail:
|
||||
wsi_wl_swapchain_destroy(&chain->base, pAllocator);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VkResult
|
||||
anv_wl_init_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
VkPhysicalDevice physical_device,
|
||||
const struct anv_wsi_callbacks *cbs)
|
||||
{
|
||||
struct wsi_wayland *wsi;
|
||||
VkResult result;
|
||||
|
||||
wsi = vk_alloc(alloc, sizeof(*wsi), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!wsi) {
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wsi->physical_device = physical_device;
|
||||
wsi->alloc = alloc;
|
||||
wsi->cbs = cbs;
|
||||
int ret = pthread_mutex_init(&wsi->mutex, NULL);
|
||||
if (ret != 0) {
|
||||
if (ret == ENOMEM) {
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
} else {
|
||||
/* FINISHME: Choose a better error. */
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
wsi->displays = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
|
||||
_mesa_key_pointer_equal);
|
||||
if (!wsi->displays) {
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
goto fail_mutex;
|
||||
}
|
||||
|
||||
wsi->base.get_support = wsi_wl_surface_get_support;
|
||||
wsi->base.get_capabilities = wsi_wl_surface_get_capabilities;
|
||||
wsi->base.get_formats = wsi_wl_surface_get_formats;
|
||||
wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;
|
||||
wsi->base.create_swapchain = wsi_wl_surface_create_swapchain;
|
||||
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_mutex:
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
|
||||
fail_alloc:
|
||||
vk_free(alloc, wsi);
|
||||
fail:
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
anv_wl_finish_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc)
|
||||
{
|
||||
struct wsi_wayland *wsi =
|
||||
(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
|
||||
|
||||
if (wsi) {
|
||||
_mesa_hash_table_destroy(wsi->displays, NULL);
|
||||
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
|
||||
vk_free(alloc, wsi);
|
||||
}
|
||||
}
|
||||
35
src/intel/vulkan/wsi_common_wayland.h
Normal file
35
src/intel/vulkan/wsi_common_wayland.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright © 2015 Intel 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.
|
||||
*/
|
||||
#ifndef WSI_COMMON_WAYLAND_H
|
||||
#define WSI_COMMON_WAYLAND_H
|
||||
|
||||
#include "wsi_common.h"
|
||||
|
||||
VkBool32
|
||||
wsi_wl_get_presentation_support(struct anv_wsi_device *wsi_device,
|
||||
struct wl_display *wl_display);
|
||||
|
||||
VkResult anv_create_wl_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface);
|
||||
#endif
|
||||
884
src/intel/vulkan/wsi_common_x11.c
Normal file
884
src/intel/vulkan/wsi_common_x11.c
Normal file
|
|
@ -0,0 +1,884 @@
|
|||
/*
|
||||
* Copyright © 2015 Intel 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 <X11/Xlib-xcb.h>
|
||||
#include <X11/xshmfence.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/dri3.h>
|
||||
#include <xcb/present.h>
|
||||
|
||||
#include "util/hash_table.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "wsi_common.h"
|
||||
#include "wsi_common_x11.h"
|
||||
|
||||
#define typed_memcpy(dest, src, count) ({ \
|
||||
static_assert(sizeof(*src) == sizeof(*dest), ""); \
|
||||
memcpy((dest), (src), (count) * sizeof(*(src))); \
|
||||
})
|
||||
|
||||
struct wsi_x11_connection {
|
||||
bool has_dri3;
|
||||
bool has_present;
|
||||
};
|
||||
|
||||
struct wsi_x11 {
|
||||
struct anv_wsi_interface base;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
/* Hash table of xcb_connection -> wsi_x11_connection mappings */
|
||||
struct hash_table *connections;
|
||||
};
|
||||
|
||||
static struct wsi_x11_connection *
|
||||
wsi_x11_connection_create(const VkAllocationCallbacks *alloc,
|
||||
xcb_connection_t *conn)
|
||||
{
|
||||
xcb_query_extension_cookie_t dri3_cookie, pres_cookie;
|
||||
xcb_query_extension_reply_t *dri3_reply, *pres_reply;
|
||||
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
vk_alloc(alloc, sizeof(*wsi_conn), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!wsi_conn)
|
||||
return NULL;
|
||||
|
||||
dri3_cookie = xcb_query_extension(conn, 4, "DRI3");
|
||||
pres_cookie = xcb_query_extension(conn, 7, "PRESENT");
|
||||
|
||||
dri3_reply = xcb_query_extension_reply(conn, dri3_cookie, NULL);
|
||||
pres_reply = xcb_query_extension_reply(conn, pres_cookie, NULL);
|
||||
if (dri3_reply == NULL || pres_reply == NULL) {
|
||||
free(dri3_reply);
|
||||
free(pres_reply);
|
||||
vk_free(alloc, wsi_conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wsi_conn->has_dri3 = dri3_reply->present != 0;
|
||||
wsi_conn->has_present = pres_reply->present != 0;
|
||||
|
||||
free(dri3_reply);
|
||||
free(pres_reply);
|
||||
|
||||
return wsi_conn;
|
||||
}
|
||||
|
||||
static void
|
||||
wsi_x11_connection_destroy(const VkAllocationCallbacks *alloc,
|
||||
struct wsi_x11_connection *conn)
|
||||
{
|
||||
vk_free(alloc, conn);
|
||||
}
|
||||
|
||||
static struct wsi_x11_connection *
|
||||
wsi_x11_get_connection(struct anv_wsi_device *wsi_dev,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
xcb_connection_t *conn)
|
||||
{
|
||||
struct wsi_x11 *wsi =
|
||||
(struct wsi_x11 *)wsi_dev->wsi[VK_ICD_WSI_PLATFORM_XCB];
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
struct hash_entry *entry = _mesa_hash_table_search(wsi->connections, conn);
|
||||
if (!entry) {
|
||||
/* We're about to make a bunch of blocking calls. Let's drop the
|
||||
* mutex for now so we don't block up too badly.
|
||||
*/
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
wsi_x11_connection_create(alloc, conn);
|
||||
|
||||
pthread_mutex_lock(&wsi->mutex);
|
||||
|
||||
entry = _mesa_hash_table_search(wsi->connections, conn);
|
||||
if (entry) {
|
||||
/* Oops, someone raced us to it */
|
||||
wsi_x11_connection_destroy(alloc, wsi_conn);
|
||||
} else {
|
||||
entry = _mesa_hash_table_insert(wsi->connections, conn, wsi_conn);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&wsi->mutex);
|
||||
|
||||
return entry->data;
|
||||
}
|
||||
|
||||
static const VkSurfaceFormatKHR formats[] = {
|
||||
{ .format = VK_FORMAT_B8G8R8A8_SRGB, },
|
||||
{ .format = VK_FORMAT_B8G8R8A8_UNORM, },
|
||||
};
|
||||
|
||||
static const VkPresentModeKHR present_modes[] = {
|
||||
VK_PRESENT_MODE_MAILBOX_KHR,
|
||||
};
|
||||
|
||||
static xcb_screen_t *
|
||||
get_screen_for_root(xcb_connection_t *conn, xcb_window_t root)
|
||||
{
|
||||
xcb_screen_iterator_t screen_iter =
|
||||
xcb_setup_roots_iterator(xcb_get_setup(conn));
|
||||
|
||||
for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
|
||||
if (screen_iter.data->root == root)
|
||||
return screen_iter.data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xcb_visualtype_t *
|
||||
screen_get_visualtype(xcb_screen_t *screen, xcb_visualid_t visual_id,
|
||||
unsigned *depth)
|
||||
{
|
||||
xcb_depth_iterator_t depth_iter =
|
||||
xcb_screen_allowed_depths_iterator(screen);
|
||||
|
||||
for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
|
||||
xcb_visualtype_iterator_t visual_iter =
|
||||
xcb_depth_visuals_iterator (depth_iter.data);
|
||||
|
||||
for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
|
||||
if (visual_iter.data->visual_id == visual_id) {
|
||||
if (depth)
|
||||
*depth = depth_iter.data->depth;
|
||||
return visual_iter.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xcb_visualtype_t *
|
||||
connection_get_visualtype(xcb_connection_t *conn, xcb_visualid_t visual_id,
|
||||
unsigned *depth)
|
||||
{
|
||||
xcb_screen_iterator_t screen_iter =
|
||||
xcb_setup_roots_iterator(xcb_get_setup(conn));
|
||||
|
||||
/* For this we have to iterate over all of the screens which is rather
|
||||
* annoying. Fortunately, there is probably only 1.
|
||||
*/
|
||||
for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
|
||||
xcb_visualtype_t *visual = screen_get_visualtype(screen_iter.data,
|
||||
visual_id, depth);
|
||||
if (visual)
|
||||
return visual;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xcb_visualtype_t *
|
||||
get_visualtype_for_window(xcb_connection_t *conn, xcb_window_t window,
|
||||
unsigned *depth)
|
||||
{
|
||||
xcb_query_tree_cookie_t tree_cookie;
|
||||
xcb_get_window_attributes_cookie_t attrib_cookie;
|
||||
xcb_query_tree_reply_t *tree;
|
||||
xcb_get_window_attributes_reply_t *attrib;
|
||||
|
||||
tree_cookie = xcb_query_tree(conn, window);
|
||||
attrib_cookie = xcb_get_window_attributes(conn, window);
|
||||
|
||||
tree = xcb_query_tree_reply(conn, tree_cookie, NULL);
|
||||
attrib = xcb_get_window_attributes_reply(conn, attrib_cookie, NULL);
|
||||
if (attrib == NULL || tree == NULL) {
|
||||
free(attrib);
|
||||
free(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xcb_window_t root = tree->root;
|
||||
xcb_visualid_t visual_id = attrib->visual;
|
||||
free(attrib);
|
||||
free(tree);
|
||||
|
||||
xcb_screen_t *screen = get_screen_for_root(conn, root);
|
||||
if (screen == NULL)
|
||||
return NULL;
|
||||
|
||||
return screen_get_visualtype(screen, visual_id, depth);
|
||||
}
|
||||
|
||||
static bool
|
||||
visual_has_alpha(xcb_visualtype_t *visual, unsigned depth)
|
||||
{
|
||||
uint32_t rgb_mask = visual->red_mask |
|
||||
visual->green_mask |
|
||||
visual->blue_mask;
|
||||
|
||||
uint32_t all_mask = 0xffffffff >> (32 - depth);
|
||||
|
||||
/* Do we have bits left over after RGB? */
|
||||
return (all_mask & ~rgb_mask) != 0;
|
||||
}
|
||||
|
||||
VkBool32 anv_get_physical_device_xcb_presentation_support(
|
||||
struct anv_wsi_device *wsi_device,
|
||||
VkAllocationCallbacks *alloc,
|
||||
uint32_t queueFamilyIndex,
|
||||
xcb_connection_t* connection,
|
||||
xcb_visualid_t visual_id)
|
||||
{
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
wsi_x11_get_connection(wsi_device, alloc, connection);
|
||||
|
||||
if (!wsi_conn->has_dri3) {
|
||||
fprintf(stderr, "vulkan: No DRI3 support\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned visual_depth;
|
||||
if (!connection_get_visualtype(connection, visual_id, &visual_depth))
|
||||
return false;
|
||||
|
||||
if (visual_depth != 24 && visual_depth != 32)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static xcb_connection_t*
|
||||
x11_surface_get_connection(VkIcdSurfaceBase *icd_surface)
|
||||
{
|
||||
if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
|
||||
return XGetXCBConnection(((VkIcdSurfaceXlib *)icd_surface)->dpy);
|
||||
else
|
||||
return ((VkIcdSurfaceXcb *)icd_surface)->connection;
|
||||
}
|
||||
|
||||
static xcb_window_t
|
||||
x11_surface_get_window(VkIcdSurfaceBase *icd_surface)
|
||||
{
|
||||
if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
|
||||
return ((VkIcdSurfaceXlib *)icd_surface)->window;
|
||||
else
|
||||
return ((VkIcdSurfaceXcb *)icd_surface)->window;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_support(VkIcdSurfaceBase *icd_surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc,
|
||||
uint32_t queueFamilyIndex,
|
||||
VkBool32* pSupported)
|
||||
{
|
||||
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
|
||||
xcb_window_t window = x11_surface_get_window(icd_surface);
|
||||
|
||||
struct wsi_x11_connection *wsi_conn =
|
||||
wsi_x11_get_connection(wsi_device, alloc, conn);
|
||||
if (!wsi_conn)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
if (!wsi_conn->has_dri3) {
|
||||
fprintf(stderr, "vulkan: No DRI3 support\n");
|
||||
*pSupported = false;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
unsigned visual_depth;
|
||||
if (!get_visualtype_for_window(conn, window, &visual_depth)) {
|
||||
*pSupported = false;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
if (visual_depth != 24 && visual_depth != 32) {
|
||||
*pSupported = false;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
*pSupported = true;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_capabilities(VkIcdSurfaceBase *icd_surface,
|
||||
VkSurfaceCapabilitiesKHR *caps)
|
||||
{
|
||||
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
|
||||
xcb_window_t window = x11_surface_get_window(icd_surface);
|
||||
xcb_get_geometry_cookie_t geom_cookie;
|
||||
xcb_generic_error_t *err;
|
||||
xcb_get_geometry_reply_t *geom;
|
||||
unsigned visual_depth;
|
||||
|
||||
geom_cookie = xcb_get_geometry(conn, window);
|
||||
|
||||
/* This does a round-trip. This is why we do get_geometry first and
|
||||
* wait to read the reply until after we have a visual.
|
||||
*/
|
||||
xcb_visualtype_t *visual =
|
||||
get_visualtype_for_window(conn, window, &visual_depth);
|
||||
|
||||
geom = xcb_get_geometry_reply(conn, geom_cookie, &err);
|
||||
if (geom) {
|
||||
VkExtent2D extent = { geom->width, geom->height };
|
||||
caps->currentExtent = extent;
|
||||
caps->minImageExtent = extent;
|
||||
caps->maxImageExtent = extent;
|
||||
} else {
|
||||
/* This can happen if the client didn't wait for the configure event
|
||||
* to come back from the compositor. In that case, we don't know the
|
||||
* size of the window so we just return valid "I don't know" stuff.
|
||||
*/
|
||||
caps->currentExtent = (VkExtent2D) { -1, -1 };
|
||||
caps->minImageExtent = (VkExtent2D) { 1, 1 };
|
||||
caps->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
|
||||
}
|
||||
free(err);
|
||||
free(geom);
|
||||
|
||||
if (visual_has_alpha(visual, visual_depth)) {
|
||||
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
|
||||
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
|
||||
} else {
|
||||
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
|
||||
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
}
|
||||
|
||||
caps->minImageCount = 2;
|
||||
caps->maxImageCount = 4;
|
||||
caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
caps->maxImageArrayLayers = 1;
|
||||
caps->supportedUsageFlags =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_formats(VkIcdSurfaceBase *surface,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
uint32_t *pSurfaceFormatCount,
|
||||
VkSurfaceFormatKHR *pSurfaceFormats)
|
||||
{
|
||||
if (pSurfaceFormats == NULL) {
|
||||
*pSurfaceFormatCount = ARRAY_SIZE(formats);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pSurfaceFormatCount >= ARRAY_SIZE(formats));
|
||||
typed_memcpy(pSurfaceFormats, formats, *pSurfaceFormatCount);
|
||||
*pSurfaceFormatCount = ARRAY_SIZE(formats);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_get_present_modes(VkIcdSurfaceBase *surface,
|
||||
uint32_t *pPresentModeCount,
|
||||
VkPresentModeKHR *pPresentModes)
|
||||
{
|
||||
if (pPresentModes == NULL) {
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(*pPresentModeCount >= ARRAY_SIZE(present_modes));
|
||||
typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
|
||||
*pPresentModeCount = ARRAY_SIZE(present_modes);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult anv_create_xcb_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface)
|
||||
{
|
||||
VkIcdSurfaceXcb *surface;
|
||||
|
||||
surface = vk_alloc(pAllocator, sizeof *surface, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (surface == NULL)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
surface->base.platform = VK_ICD_WSI_PLATFORM_XCB;
|
||||
surface->connection = pCreateInfo->connection;
|
||||
surface->window = pCreateInfo->window;
|
||||
|
||||
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult anv_create_xlib_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface)
|
||||
{
|
||||
VkIcdSurfaceXlib *surface;
|
||||
|
||||
surface = vk_alloc(pAllocator, sizeof *surface, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (surface == NULL)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
surface->base.platform = VK_ICD_WSI_PLATFORM_XLIB;
|
||||
surface->dpy = pCreateInfo->dpy;
|
||||
surface->window = pCreateInfo->window;
|
||||
|
||||
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
struct x11_image {
|
||||
VkImage image;
|
||||
VkDeviceMemory memory;
|
||||
xcb_pixmap_t pixmap;
|
||||
bool busy;
|
||||
struct xshmfence * shm_fence;
|
||||
uint32_t sync_fence;
|
||||
};
|
||||
|
||||
struct x11_swapchain {
|
||||
struct anv_swapchain base;
|
||||
|
||||
xcb_connection_t * conn;
|
||||
xcb_window_t window;
|
||||
xcb_gc_t gc;
|
||||
VkExtent2D extent;
|
||||
uint32_t image_count;
|
||||
|
||||
xcb_present_event_t event_id;
|
||||
xcb_special_event_t * special_event;
|
||||
uint64_t send_sbc;
|
||||
uint32_t stamp;
|
||||
|
||||
struct x11_image images[0];
|
||||
};
|
||||
|
||||
static VkResult
|
||||
x11_get_images(struct anv_swapchain *anv_chain,
|
||||
uint32_t* pCount, VkImage *pSwapchainImages)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
|
||||
if (pSwapchainImages == NULL) {
|
||||
*pCount = chain->image_count;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
assert(chain->image_count <= *pCount);
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
pSwapchainImages[i] = chain->images[i].image;
|
||||
|
||||
*pCount = chain->image_count;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_handle_dri3_present_event(struct x11_swapchain *chain,
|
||||
xcb_present_generic_event_t *event)
|
||||
{
|
||||
switch (event->evtype) {
|
||||
case XCB_PRESENT_CONFIGURE_NOTIFY: {
|
||||
xcb_present_configure_notify_event_t *config = (void *) event;
|
||||
|
||||
if (config->width != chain->extent.width ||
|
||||
config->height != chain->extent.height)
|
||||
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
|
||||
xcb_present_idle_notify_event_t *idle = (void *) event;
|
||||
|
||||
for (unsigned i = 0; i < chain->image_count; i++) {
|
||||
if (chain->images[i].pixmap == idle->pixmap) {
|
||||
chain->images[i].busy = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case XCB_PRESENT_COMPLETE_NOTIFY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_acquire_next_image(struct anv_swapchain *anv_chain,
|
||||
uint64_t timeout,
|
||||
VkSemaphore semaphore,
|
||||
uint32_t *image_index)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
|
||||
while (1) {
|
||||
for (uint32_t i = 0; i < chain->image_count; i++) {
|
||||
if (!chain->images[i].busy) {
|
||||
/* We found a non-busy image */
|
||||
xshmfence_await(chain->images[i].shm_fence);
|
||||
*image_index = i;
|
||||
chain->images[i].busy = true;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
xcb_flush(chain->conn);
|
||||
xcb_generic_event_t *event =
|
||||
xcb_wait_for_special_event(chain->conn, chain->special_event);
|
||||
if (!event)
|
||||
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||
|
||||
VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
|
||||
free(event);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_queue_present(struct anv_swapchain *anv_chain,
|
||||
uint32_t image_index)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
struct x11_image *image = &chain->images[image_index];
|
||||
|
||||
assert(image_index < chain->image_count);
|
||||
|
||||
uint32_t options = XCB_PRESENT_OPTION_NONE;
|
||||
|
||||
int64_t target_msc = 0;
|
||||
int64_t divisor = 0;
|
||||
int64_t remainder = 0;
|
||||
|
||||
options |= XCB_PRESENT_OPTION_ASYNC;
|
||||
|
||||
xshmfence_reset(image->shm_fence);
|
||||
|
||||
++chain->send_sbc;
|
||||
xcb_void_cookie_t cookie =
|
||||
xcb_present_pixmap(chain->conn,
|
||||
chain->window,
|
||||
image->pixmap,
|
||||
(uint32_t) chain->send_sbc,
|
||||
0, /* valid */
|
||||
0, /* update */
|
||||
0, /* x_off */
|
||||
0, /* y_off */
|
||||
XCB_NONE, /* target_crtc */
|
||||
XCB_NONE,
|
||||
image->sync_fence,
|
||||
options,
|
||||
target_msc,
|
||||
divisor,
|
||||
remainder, 0, NULL);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
image->busy = true;
|
||||
|
||||
xcb_flush(chain->conn);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
|
||||
const VkSwapchainCreateInfoKHR *pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
struct x11_image *image)
|
||||
{
|
||||
xcb_void_cookie_t cookie;
|
||||
VkResult result;
|
||||
uint32_t row_pitch;
|
||||
uint32_t offset;
|
||||
uint32_t bpp = 32;
|
||||
uint32_t depth = 24;
|
||||
int fd;
|
||||
uint32_t size;
|
||||
|
||||
result = chain->base.image_fns->create_wsi_image(device_h,
|
||||
pCreateInfo,
|
||||
pAllocator,
|
||||
&image->image,
|
||||
&image->memory,
|
||||
&size,
|
||||
&offset,
|
||||
&row_pitch,
|
||||
&fd);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
image->pixmap = xcb_generate_id(chain->conn);
|
||||
|
||||
cookie =
|
||||
xcb_dri3_pixmap_from_buffer_checked(chain->conn,
|
||||
image->pixmap,
|
||||
chain->window,
|
||||
size,
|
||||
pCreateInfo->imageExtent.width,
|
||||
pCreateInfo->imageExtent.height,
|
||||
row_pitch,
|
||||
depth, bpp, fd);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
int fence_fd = xshmfence_alloc_shm();
|
||||
if (fence_fd < 0)
|
||||
goto fail_pixmap;
|
||||
|
||||
image->shm_fence = xshmfence_map_shm(fence_fd);
|
||||
if (image->shm_fence == NULL)
|
||||
goto fail_shmfence_alloc;
|
||||
|
||||
image->sync_fence = xcb_generate_id(chain->conn);
|
||||
xcb_dri3_fence_from_fd(chain->conn,
|
||||
image->pixmap,
|
||||
image->sync_fence,
|
||||
false,
|
||||
fence_fd);
|
||||
|
||||
image->busy = false;
|
||||
xshmfence_trigger(image->shm_fence);
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_shmfence_alloc:
|
||||
close(fence_fd);
|
||||
|
||||
fail_pixmap:
|
||||
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
chain->base.image_fns->free_wsi_image(device_h, pAllocator,
|
||||
image->image, image->memory);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
x11_image_finish(struct x11_swapchain *chain,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
struct x11_image *image)
|
||||
{
|
||||
xcb_void_cookie_t cookie;
|
||||
|
||||
cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
xshmfence_unmap_shm(image->shm_fence);
|
||||
|
||||
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
chain->base.image_fns->free_wsi_image(chain->base.device, pAllocator,
|
||||
image->image, image->memory);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_swapchain_destroy(struct anv_swapchain *anv_chain,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
|
||||
for (uint32_t i = 0; i < chain->image_count; i++)
|
||||
x11_image_finish(chain, pAllocator, &chain->images[i]);
|
||||
|
||||
xcb_unregister_for_special_event(chain->conn, chain->special_event);
|
||||
|
||||
vk_free(pAllocator, chain);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
|
||||
VkDevice device,
|
||||
struct anv_wsi_device *wsi_device,
|
||||
const VkSwapchainCreateInfoKHR *pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
const struct anv_wsi_image_fns *image_fns,
|
||||
struct anv_swapchain **swapchain_out)
|
||||
{
|
||||
struct x11_swapchain *chain;
|
||||
xcb_void_cookie_t cookie;
|
||||
VkResult result;
|
||||
|
||||
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
|
||||
|
||||
int num_images = pCreateInfo->minImageCount;
|
||||
|
||||
/* For true mailbox mode, we need at least 4 images:
|
||||
* 1) One to scan out from
|
||||
* 2) One to have queued for scan-out
|
||||
* 3) One to be currently held by the Wayland compositor
|
||||
* 4) One to render to
|
||||
*/
|
||||
if (pCreateInfo->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
|
||||
num_images = MAX2(num_images, 4);
|
||||
|
||||
size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
|
||||
chain = vk_alloc(pAllocator, size, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (chain == NULL)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
chain->base.device = device;
|
||||
chain->base.destroy = x11_swapchain_destroy;
|
||||
chain->base.get_images = x11_get_images;
|
||||
chain->base.acquire_next_image = x11_acquire_next_image;
|
||||
chain->base.queue_present = x11_queue_present;
|
||||
chain->base.image_fns = image_fns;
|
||||
chain->conn = x11_surface_get_connection(icd_surface);
|
||||
chain->window = x11_surface_get_window(icd_surface);
|
||||
chain->extent = pCreateInfo->imageExtent;
|
||||
chain->image_count = num_images;
|
||||
chain->send_sbc = 0;
|
||||
|
||||
chain->event_id = xcb_generate_id(chain->conn);
|
||||
xcb_present_select_input(chain->conn, chain->event_id, chain->window,
|
||||
XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
|
||||
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
|
||||
XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
|
||||
|
||||
/* Create an XCB event queue to hold present events outside of the usual
|
||||
* application event queue
|
||||
*/
|
||||
chain->special_event =
|
||||
xcb_register_for_special_xge(chain->conn, &xcb_present_id,
|
||||
chain->event_id, NULL);
|
||||
|
||||
chain->gc = xcb_generate_id(chain->conn);
|
||||
if (!chain->gc) {
|
||||
/* FINISHME: Choose a better error. */
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
goto fail_register;
|
||||
}
|
||||
|
||||
cookie = xcb_create_gc(chain->conn,
|
||||
chain->gc,
|
||||
chain->window,
|
||||
XCB_GC_GRAPHICS_EXPOSURES,
|
||||
(uint32_t []) { 0 });
|
||||
xcb_discard_reply(chain->conn, cookie.sequence);
|
||||
|
||||
uint32_t image = 0;
|
||||
for (; image < chain->image_count; image++) {
|
||||
result = x11_image_init(device, chain, pCreateInfo, pAllocator,
|
||||
&chain->images[image]);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_init_images;
|
||||
}
|
||||
|
||||
*swapchain_out = &chain->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_init_images:
|
||||
for (uint32_t j = 0; j < image; j++)
|
||||
x11_image_finish(chain, pAllocator, &chain->images[j]);
|
||||
|
||||
fail_register:
|
||||
xcb_unregister_for_special_event(chain->conn, chain->special_event);
|
||||
|
||||
vk_free(pAllocator, chain);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VkResult
|
||||
anv_x11_init_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc)
|
||||
{
|
||||
struct wsi_x11 *wsi;
|
||||
VkResult result;
|
||||
|
||||
wsi = vk_alloc(alloc, sizeof(*wsi), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
||||
if (!wsi) {
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int ret = pthread_mutex_init(&wsi->mutex, NULL);
|
||||
if (ret != 0) {
|
||||
if (ret == ENOMEM) {
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
} else {
|
||||
/* FINISHME: Choose a better error. */
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
}
|
||||
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
wsi->connections = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
|
||||
_mesa_key_pointer_equal);
|
||||
if (!wsi->connections) {
|
||||
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
goto fail_mutex;
|
||||
}
|
||||
|
||||
wsi->base.get_support = x11_surface_get_support;
|
||||
wsi->base.get_capabilities = x11_surface_get_capabilities;
|
||||
wsi->base.get_formats = x11_surface_get_formats;
|
||||
wsi->base.get_present_modes = x11_surface_get_present_modes;
|
||||
wsi->base.create_swapchain = x11_surface_create_swapchain;
|
||||
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = &wsi->base;
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_mutex:
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
fail_alloc:
|
||||
vk_free(alloc, wsi);
|
||||
fail:
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB] = NULL;
|
||||
wsi_device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
anv_x11_finish_wsi(struct anv_wsi_device *wsi_device,
|
||||
const VkAllocationCallbacks *alloc)
|
||||
{
|
||||
struct wsi_x11 *wsi =
|
||||
(struct wsi_x11 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_XCB];
|
||||
|
||||
if (wsi) {
|
||||
_mesa_hash_table_destroy(wsi->connections, NULL);
|
||||
|
||||
pthread_mutex_destroy(&wsi->mutex);
|
||||
|
||||
vk_free(alloc, wsi);
|
||||
}
|
||||
}
|
||||
42
src/intel/vulkan/wsi_common_x11.h
Normal file
42
src/intel/vulkan/wsi_common_x11.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright © 2015 Intel 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.
|
||||
*/
|
||||
#ifndef WSI_COMMON_X11_H
|
||||
#define WSI_COMMON_X11_H
|
||||
|
||||
#include "wsi_common.h"
|
||||
|
||||
VkBool32 anv_get_physical_device_xcb_presentation_support(
|
||||
struct anv_wsi_device *wsi_device,
|
||||
VkAllocationCallbacks *alloc,
|
||||
uint32_t queueFamilyIndex,
|
||||
xcb_connection_t* connection,
|
||||
xcb_visualid_t visual_id);
|
||||
|
||||
VkResult anv_create_xcb_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkXcbSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface);
|
||||
|
||||
VkResult anv_create_xlib_surface(const VkAllocationCallbacks *pAllocator,
|
||||
const VkXlibSurfaceCreateInfoKHR *pCreateInfo,
|
||||
VkSurfaceKHR *pSurface);
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue