summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg Kristensen <kristian.h.kristensen@intel.com>2016-04-06 11:33:54 -0700
committerKristian Høgsberg Kristensen <kristian.h.kristensen@intel.com>2016-04-06 11:33:54 -0700
commit4f4d1d507226177cdef55e2c8de8aa769099c5a3 (patch)
treeec4a1ce57fbaa59f74226d6b4ad31cd453ad52fe
parent6d658e9bd546581a0841e7acb8915dc05d44c628 (diff)
downloadmesa-wayland-bind-display.tar.gz
anv/wip: wayland bind display extensionwayland-bind-display
-rw-r--r--src/intel/vulkan/Makefile.am8
-rw-r--r--src/intel/vulkan/anv_device.c10
-rw-r--r--src/intel/vulkan/anv_gem.c16
-rw-r--r--src/intel/vulkan/anv_private.h2
-rw-r--r--src/intel/vulkan/anv_wayland.c462
5 files changed, 497 insertions, 1 deletions
diff --git a/src/intel/vulkan/Makefile.am b/src/intel/vulkan/Makefile.am
index acf84e55871..1b64d37a350 100644
--- a/src/intel/vulkan/Makefile.am
+++ b/src/intel/vulkan/Makefile.am
@@ -26,7 +26,8 @@ vulkan_includedir = $(includedir)/vulkan
vulkan_include_HEADERS = \
$(top_srcdir)/include/vulkan/vk_platform.h \
$(top_srcdir)/include/vulkan/vulkan.h \
- $(top_srcdir)/include/vulkan/vulkan_intel.h
+ $(top_srcdir)/include/vulkan/vulkan_intel.h \
+ $(top_srcdir)/include/vulkan/vulkan_wayland.h
# Used when generating entrypoints to filter out unwanted extensions
VULKAN_ENTRYPOINT_CPPFLAGS = \
@@ -138,6 +139,7 @@ libanv_gen9_la_CFLAGS = $(libvulkan_intel_la_CFLAGS) -DGEN_VERSIONx10=90
if HAVE_EGL_PLATFORM_WAYLAND
BUILT_SOURCES += \
wayland-drm-protocol.c \
+ wayland-drm-server-protocol.h \
wayland-drm-client-protocol.h
%-protocol.c : $(top_srcdir)/src/egl/wayland/wayland-drm/%.xml
@@ -146,9 +148,13 @@ BUILT_SOURCES += \
%-client-protocol.h : $(top_srcdir)/src/egl/wayland/wayland-drm/%.xml
$(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@
+%-server-protocol.h : $(top_srcdir)/src/egl/wayland/wayland-drm/%.xml
+ $(AM_V_GEN)$(WAYLAND_SCANNER) server-header < $< > $@
+
AM_CPPFLAGS += -I$(top_srcdir)/src/egl/wayland/wayland-drm
VULKAN_SOURCES += \
wayland-drm-protocol.c \
+ anv_wayland.c \
anv_wsi_wayland.c
libvulkan_intel_la_CFLAGS += -DHAVE_WAYLAND_PLATFORM
endif
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 54a1f1274ab..a3d2cf7ea55 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -124,6 +124,16 @@ anv_physical_device_init(struct anv_physical_device *device,
goto fail;
}
+ uint64_t cap;
+
+ if (anv_gem_get_cap(fd, DRM_CAP_PRIME, &cap) == -1 ||
+ (cap & DRM_PRIME_CAP_IMPORT) == 0 ||
+ (cap & DRM_PRIME_CAP_EXPORT) == 0) {
+ result = vk_errorf(VK_ERROR_INITIALIZATION_FAILED,
+ "kernel missing prime import/export");
+ goto fail;
+ }
+
bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X);
close(fd);
diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c
index a886f7c2cb0..817a52010d5 100644
--- a/src/intel/vulkan/anv_gem.c
+++ b/src/intel/vulkan/anv_gem.c
@@ -214,6 +214,22 @@ anv_gem_get_param(int fd, uint32_t param)
return 0;
}
+int
+anv_gem_get_cap(int fd, uint64_t capability, uint64_t *value)
+{
+ int ret;
+ struct drm_get_cap cap = {
+ .capability = capability
+ };
+
+ ret = anv_ioctl(fd, DRM_IOCTL_GET_CAP, &cap);
+ if (ret)
+ return ret;
+
+ *value = cap.value;
+ return 0;
+}
+
bool
anv_gem_get_bit6_swizzle(int fd, uint32_t tiling)
{
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 77f453afb36..453330dfaea 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -58,6 +58,7 @@ typedef uint32_t xcb_window_t;
#define VK_PROTOTYPES
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_intel.h>
+#include <vulkan/vulkan_wayland.h>
#include <vulkan/vk_icd.h>
#include "anv_entrypoints.h"
@@ -717,6 +718,7 @@ int anv_gem_set_tiling(struct anv_device *device, uint32_t gem_handle,
int anv_gem_create_context(struct anv_device *device);
int anv_gem_destroy_context(struct anv_device *device, int context);
int anv_gem_get_param(int fd, uint32_t param);
+int anv_gem_get_cap(int fd, uint64_t capability, uint64_t *value);
bool anv_gem_get_bit6_swizzle(int fd, uint32_t tiling);
int anv_gem_get_aperture(int fd, uint64_t *size);
int anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle);
diff --git a/src/intel/vulkan/anv_wayland.c b/src/intel/vulkan/anv_wayland.c
new file mode 100644
index 00000000000..c29021fca5f
--- /dev/null
+++ b/src/intel/vulkan/anv_wayland.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright © 2016 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-server-protocol.h>
+
+#include "anv_private.h"
+
+struct anv_wl_drm {
+ struct wl_display * wl_display;
+ struct wl_global * wl_drm_global;
+
+ struct anv_device * device;
+ const VkAllocationCallbacks* alloc;
+
+ char * device_name;
+};
+
+struct buffer_layout {
+ uint32_t fourcc;
+ uint32_t components;
+ uint32_t nplanes;
+ struct image_plane {
+ int buffer_index;
+ int width_shift;
+ int height_shift;
+ VkFormat vk_format;
+ } planes[3];
+};
+
+#define COMPONENTS_RGB 0x3001
+#define COMPONENTS_RGBA 0x3002
+#define COMPONENTS_Y_U_V 0x3003
+#define COMPONENTS_Y_UV 0x3004
+#define COMPONENTS_Y_XUXV 0x3005
+#define COMPONENTS_R 0x3006
+#define COMPONENTS_RG 0x3007
+
+struct anv_wl_buffer {
+ struct wl_resource * resource;
+ VkExtent3D extent;
+ const struct buffer_layout * layout;
+ struct anv_bo bo;
+ VkImage images[3];
+
+ int refcount;
+};
+
+static void
+buffer_deref(struct anv_wl_buffer *buffer)
+{
+ buffer->refcount--;
+ if (buffer->refcount > 0)
+ return;
+
+ for (uint32_t i = 0; i < buffer->layout->nplanes; i++) {
+ anv_DestroyImage(anv_device_to_handle(drm->device),
+ buffer->images[i], drm->alloc);
+ }
+
+ anv_gem_close(drm->device, buffer->bo.gem_handle);
+
+ anv_free(drm->alloc, buffer);
+}
+
+static void
+destroy_buffer(struct wl_resource *resource)
+{
+ buffer_deref(resource->data);
+}
+
+static void
+buffer_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_buffer_interface buffer_interface = {
+ .destroy = buffer_destroy
+};
+
+static void
+drm_create_buffer(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, uint32_t name, int32_t width, int32_t height,
+ uint32_t stride, uint32_t format)
+{
+ wl_resource_post_error(resource,
+ WL_DRM_ERROR_INVALID_NAME,
+ "only prime buffers supported");
+}
+
+static void
+drm_create_planar_buffer(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id, uint32_t name,
+ int32_t width, int32_t height, uint32_t format,
+ int32_t offset0, int32_t stride0,
+ int32_t offset1, int32_t stride1,
+ int32_t offset2, int32_t stride2)
+{
+ wl_resource_post_error(resource,
+ WL_DRM_ERROR_INVALID_NAME,
+ "only prime buffers supported");
+}
+
+static const struct buffer_layout buffer_layouts[] = {
+ { WL_DRM_FORMAT_ARGB8888, COMPONENTS_RGBA, 1,
+ { { 0, 0, 0, VK_FORMAT_B8G8R8A8_UNORM } } },
+
+ { WL_DRM_FORMAT_ABGR8888, COMPONENTS_RGBA, 1,
+ { { 0, 0, 0, VK_FORMAT_R8G8B8A8_UNORM } } },
+
+ { WL_DRM_FORMAT_XRGB8888, COMPONENTS_RGB, 1,
+ { { 0, 0, 0, VK_FORMAT_B8G8R8A8_UNORM }, } },
+
+ { WL_DRM_FORMAT_XBGR8888, COMPONENTS_RGB, 1,
+ { { 0, 0, 0, VK_FORMAT_R8G8B8A8_UNORM }, } },
+
+ { WL_DRM_FORMAT_RGB565, COMPONENTS_RGB, 1,
+ { { 0, 0, 0, VK_FORMAT_B5G6R5_UNORM_PACK16 } } },
+
+ { WL_DRM_FORMAT_YUV410, COMPONENTS_Y_U_V, 3,
+ { { 0, 0, 0, VK_FORMAT_R8_UNORM },
+ { 1, 2, 2, VK_FORMAT_R8_UNORM },
+ { 2, 2, 2, VK_FORMAT_R8_UNORM } } },
+
+ { WL_DRM_FORMAT_YUV411, COMPONENTS_Y_U_V, 3,
+ { { 0, 0, 0, VK_FORMAT_R8_UNORM },
+ { 1, 2, 0, VK_FORMAT_R8_UNORM },
+ { 2, 2, 0, VK_FORMAT_R8_UNORM } } },
+
+ { WL_DRM_FORMAT_YUV420, COMPONENTS_Y_U_V, 3,
+ { { 0, 0, 0, VK_FORMAT_R8_UNORM },
+ { 1, 1, 1, VK_FORMAT_R8_UNORM },
+ { 2, 1, 1, VK_FORMAT_R8_UNORM } } },
+
+ { WL_DRM_FORMAT_YUV422, COMPONENTS_Y_U_V, 3,
+ { { 0, 0, 0, VK_FORMAT_R8_UNORM },
+ { 1, 1, 0, VK_FORMAT_R8_UNORM },
+ { 2, 1, 0, VK_FORMAT_R8_UNORM } } },
+
+ { WL_DRM_FORMAT_YUV444, COMPONENTS_Y_U_V, 3,
+ { { 0, 0, 0, VK_FORMAT_R8_UNORM },
+ { 1, 0, 0, VK_FORMAT_R8_UNORM },
+ { 2, 0, 0, VK_FORMAT_R8_UNORM } } },
+
+ { WL_DRM_FORMAT_NV12, COMPONENTS_Y_UV, 2,
+ { { 0, 0, 0, VK_FORMAT_R8_UNORM },
+ { 1, 1, 1, VK_FORMAT_R8G8_UNORM } } },
+
+ { WL_DRM_FORMAT_NV16, COMPONENTS_Y_UV, 2,
+ { { 0, 0, 0, VK_FORMAT_R8_UNORM },
+ { 1, 1, 0, VK_FORMAT_R8G8_UNORM } } },
+
+ /* For YUYV buffers, we set up two overlapping DRI images and treat them as
+ * planar buffers in the compositors. Plane 0 is RG88 and samples YU or YV
+ * pairs and places Y into the R component, while plane 1 is ARGB8888 and
+ * samples YUYV clusters and places U into the G component and V into A.
+ * This lets the texture sampler filter the Y components correctly when
+ * sampling from plane 0, and filter U and V correctly when sampling from
+ * plane 1. */
+ { WL_DRM_FORMAT_YUYV, COMPONENTS_Y_XUXV, 2,
+ { { 0, 0, 0, VK_FORMAT_R8G8_UNORM },
+ { 0, 1, 0, VK_FORMAT_B8G8R8A8_UNORM } } }
+};
+
+static const struct buffer_layout *
+lookup_layout(uint32_t wl_format)
+{
+ for (uint32_t i = 0; i < ARRAY_SIZE(buffer_layouts); i++) {
+ if (buffer_layouts[i].fourcc == wl_format)
+ return &buffer_layouts[i];
+ }
+
+ return NULL;
+}
+
+static void
+drm_create_prime_buffer(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id, int fd,
+ int32_t width, int32_t height, uint32_t format,
+ int32_t offset0, int32_t stride0,
+ int32_t offset1, int32_t stride1,
+ int32_t offset2, int32_t stride2)
+{
+ struct anv_wl_drm *drm = resource->data;
+ struct anv_wl_buffer *buffer;
+ const struct buffer_layout *layout;
+
+ if (width <= 0 || height <= 0) {
+ wl_resource_post_error(resource,
+ WL_DRM_ERROR_INVALID_FORMAT,
+ "invalid extent");
+ goto fail_fd;
+ }
+
+ layout = lookup_layout(format);
+ if (layout == NULL) {
+ wl_resource_post_error(resource,
+ WL_DRM_ERROR_INVALID_FORMAT,
+ "invalid format");
+ goto fail_fd;
+ }
+
+ buffer = anv_alloc(drm->alloc, sizeof(*buffer), 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ if (buffer == NULL) {
+ wl_resource_post_no_memory(resource);
+ goto fail_fd;
+ }
+
+ buffer->extent.width = width;
+ buffer->extent.height = height;
+ buffer->extent.depth = 1;
+ buffer->layout = layout;
+
+ buffer->bo.gem_handle = anv_gem_fd_to_handle(drm->device, fd);
+ if (!buffer->bo.gem_handle) {
+ wl_resource_post_error(resource,
+ WL_DRM_ERROR_INVALID_NAME,
+ "invalid name");
+ goto fail_buffer;
+ }
+
+ int size;
+ size = lseek(fd, 0, SEEK_END);
+ if (size == -1) {
+ wl_resource_post_error(resource,
+ WL_DRM_ERROR_INVALID_NAME,
+ "invalid name");
+ goto fail_handle;
+ }
+
+ buffer->bo.map = NULL;
+ buffer->bo.index = 0;
+ buffer->bo.offset = 0;
+ buffer->bo.size = size;
+
+ buffer->resource =
+ wl_resource_create(client, &wl_buffer_interface, 1, id);
+ if (!buffer->resource) {
+ wl_resource_post_no_memory(resource);
+ goto fail_handle;
+ }
+
+ wl_resource_set_implementation(buffer->resource,
+ (void (**)(void)) &buffer_interface,
+ buffer, destroy_buffer);
+
+ const struct {
+ int32_t offset;
+ int32_t stride;
+ } planes[3] = {
+ { offset0, stride0 },
+ { offset1, stride1 },
+ { offset2, stride2 }
+ };
+
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < layout->nplanes; i++) {
+ const struct image_plane plane = buffer->layout->planes[i];
+ struct anv_image *image;
+
+ const VkExtent3D extent = {
+ .width = buffer->extent.width >> plane.width_shift,
+ .height = buffer->extent.height >> plane.height_shift,
+ .depth = 1
+ };
+
+ VkResult result =
+ anv_image_create(anv_device_to_handle(drm->device),
+ &(struct anv_image_create_info) {
+ .isl_tiling_flags = ISL_TILING_X_BIT,
+ .stride = planes[plane.buffer_index].stride,
+ .vk_info =
+ &(VkImageCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+ .imageType = VK_IMAGE_TYPE_2D,
+ .format = plane.vk_format,
+ .extent = extent,
+ .mipLevels = 1,
+ .arrayLayers = 1,
+ .samples = 1,
+ .tiling = VK_IMAGE_TILING_OPTIMAL,
+ .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .flags = 0,
+ }}, drm->alloc, &buffer->images[i]);
+
+ if (result != VK_SUCCESS)
+ goto fail_images;
+
+ image = anv_image_from_handle(buffer->images[i]);
+ image->bo = &buffer->bo;
+ image->offset = planes[plane.buffer_index].offset;
+ count++;
+ }
+
+ close(fd);
+ return;
+
+ fail_images:
+ for (uint32_t i = 0; i < count; i++)
+ anv_DestroyImage(anv_device_to_handle(drm->device),
+ buffer->images[i], drm->alloc);
+ fail_handle:
+ anv_gem_close(drm->device, buffer->bo.gem_handle);
+ fail_buffer:
+ anv_free(drm->alloc, buffer);
+ fail_fd:
+ close(fd);
+ return;
+}
+
+static void
+drm_authenticate(struct wl_client *client,
+ struct wl_resource *resource, uint32_t id)
+{
+ wl_resource_post_error(resource,
+ WL_DRM_ERROR_AUTHENTICATE_FAIL,
+ "authenicate not supported");
+}
+
+static const struct wl_drm_interface drm_interface = {
+ drm_authenticate,
+ drm_create_buffer,
+ drm_create_planar_buffer,
+ drm_create_prime_buffer
+};
+
+static void
+bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct anv_wl_drm *drm = data;
+ struct wl_resource *resource;
+ uint32_t capabilities;
+
+ resource = wl_resource_create(client, &wl_drm_interface,
+ MIN(version, 2), id);
+ if (!resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &drm_interface, data, NULL);
+
+ wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_ARGB8888);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_XRGB8888);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_RGB565);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV410);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV411);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV420);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV422);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV444);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16);
+ wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV);
+
+ capabilities = WL_DRM_CAPABILITY_PRIME;
+ if (version >= 2)
+ wl_resource_post_event(resource, WL_DRM_CAPABILITIES, capabilities);
+}
+
+VkResult anv_BindDisplayWL(
+ VkDevice _device,
+ const VkAllocationCallbacks* pAllocator,
+ struct wl_display * wl_dpy)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ struct anv_wl_drm *drm;
+
+ drm = anv_alloc2(&device->alloc, pAllocator, sizeof(*drm), 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ if (drm == NULL)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+ drm->device = device;
+ if (pAllocator)
+ drm->alloc = pAllocator;
+ else
+ drm->alloc = &device->alloc;
+ drm->wl_display = wl_dpy;
+
+ drm->wl_drm_global =
+ wl_global_create(wl_dpy, &wl_drm_interface, 2, drm, bind_drm);
+
+ return VK_SUCCESS;
+}
+
+
+
+VkResult anv_LockBufferImagesWL(
+ VkDevice _device,
+ struct wl_resource * buffer_resource,
+ uint32_t * pImageCount,
+ VkBufferImageWL * pImages,
+ VkExtent3D * extent)
+{
+ struct anv_wl_buffer *buffer;
+
+ /* FIXME: Need semaphores, and need to communicate formats and how
+ * components maps to images. y-inverted?
+ */
+
+ if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
+ &buffer_interface)) {
+ *pImageCount = 0;
+ return VK_SUCCESS;
+ }
+
+ buffer = wl_resource_get_user_data(buffer_resource);
+
+ *pImageCount = buffer->layout->nplanes;
+ if (pImages == NULL)
+ return VK_SUCCESS;
+
+ for (uint32_t i = 0; i < buffer->layout->nplanes; i++) {
+ pImages[i].image = buffer->images[i];
+ pImages[i].format = buffer->layout->planes[i].vk_format;
+ }
+
+ *extent = buffer->extent;
+
+ buffer->refcount++;
+
+ return VK_SUCCESS;
+}
+
+void anv_ReleaseBufferImagesWL(
+ VkDevice _device,
+ struct wl_resource * buffer_resource)
+{
+ struct anv_wl_buffer *buffer;
+
+ assert(wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
+ &buffer_interface));
+
+ buffer = wl_resource_get_user_data(buffer_resource);
+
+ buffer_deref(buffer);
+}