1/* 2 * Copyright © 2011 Kristian Høgsberg 3 * Copyright © 2011 Benjamin Franzke 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Kristian Høgsberg <krh@bitplanet.net> 27 * Benjamin Franzke <benjaminfranzke@googlemail.com> 28 */ 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <stddef.h> 34#include <unistd.h> 35 36#include <wayland-server.h> 37#include "wayland-drm.h" 38#include "wayland-drm-server-protocol.h" 39 40#define MIN(x,y) (((x)<(y))?(x):(y)) 41 42static void 43destroy_buffer(struct wl_resource *resource) 44{ 45 struct wl_drm_buffer *buffer = wl_resource_get_user_data(resource); 46 struct wl_drm *drm = buffer->drm; 47 48 drm->callbacks.release_buffer(drm->user_data, buffer); 49 free(buffer); 50} 51 52static void 53buffer_destroy(struct wl_client *client, struct wl_resource *resource) 54{ 55 wl_resource_destroy(resource); 56} 57 58static void 59create_buffer(struct wl_client *client, struct wl_resource *resource, 60 uint32_t id, uint32_t name, int fd, 61 int32_t width, int32_t height, 62 uint32_t format, 63 int32_t offset0, int32_t stride0, 64 int32_t offset1, int32_t stride1, 65 int32_t offset2, int32_t stride2) 66{ 67 struct wl_drm *drm = wl_resource_get_user_data(resource); 68 struct wl_drm_buffer *buffer; 69 70 buffer = calloc(1, sizeof *buffer); 71 if (buffer == NULL) { 72 wl_resource_post_no_memory(resource); 73 return; 74 } 75 76 buffer->drm = drm; 77 buffer->width = width; 78 buffer->height = height; 79 buffer->format = format; 80 buffer->offset[0] = offset0; 81 buffer->stride[0] = stride0; 82 buffer->offset[1] = offset1; 83 buffer->stride[1] = stride1; 84 buffer->offset[2] = offset2; 85 buffer->stride[2] = stride2; 86 87 drm->callbacks.reference_buffer(drm->user_data, name, fd, buffer); 88 if (buffer->driver_buffer == NULL) { 89 wl_resource_post_error(resource, 90 WL_DRM_ERROR_INVALID_NAME, 91 "invalid name"); 92 return; 93 } 94 95 buffer->resource = 96 wl_resource_create(client, &wl_buffer_interface, 1, id); 97 if (!buffer->resource) { 98 wl_resource_post_no_memory(resource); 99 free(buffer); 100 return; 101 } 102 103 wl_resource_set_implementation(buffer->resource, 104 (void (**)(void)) &drm->buffer_interface, 105 buffer, destroy_buffer); 106} 107 108static void 109drm_create_buffer(struct wl_client *client, struct wl_resource *resource, 110 uint32_t id, uint32_t name, int32_t width, int32_t height, 111 uint32_t stride, uint32_t format) 112{ 113 switch (format) { 114 case WL_DRM_FORMAT_ABGR2101010: 115 case WL_DRM_FORMAT_XBGR2101010: 116 case WL_DRM_FORMAT_ARGB2101010: 117 case WL_DRM_FORMAT_XRGB2101010: 118 case WL_DRM_FORMAT_ARGB8888: 119 case WL_DRM_FORMAT_XRGB8888: 120 case WL_DRM_FORMAT_YUYV: 121 case WL_DRM_FORMAT_RGB565: 122 break; 123 default: 124 wl_resource_post_error(resource, 125 WL_DRM_ERROR_INVALID_FORMAT, 126 "invalid format"); 127 return; 128 } 129 130 create_buffer(client, resource, id, 131 name, -1, width, height, format, 0, stride, 0, 0, 0, 0); 132} 133 134static void 135drm_create_planar_buffer(struct wl_client *client, 136 struct wl_resource *resource, 137 uint32_t id, uint32_t name, 138 int32_t width, int32_t height, uint32_t format, 139 int32_t offset0, int32_t stride0, 140 int32_t offset1, int32_t stride1, 141 int32_t offset2, int32_t stride2) 142{ 143 switch (format) { 144 case WL_DRM_FORMAT_YUV410: 145 case WL_DRM_FORMAT_YUV411: 146 case WL_DRM_FORMAT_YUV420: 147 case WL_DRM_FORMAT_YUV422: 148 case WL_DRM_FORMAT_YUV444: 149 case WL_DRM_FORMAT_NV12: 150 case WL_DRM_FORMAT_NV16: 151 break; 152 default: 153 wl_resource_post_error(resource, 154 WL_DRM_ERROR_INVALID_FORMAT, 155 "invalid format"); 156 return; 157 } 158 159 create_buffer(client, resource, id, name, -1, width, height, format, 160 offset0, stride0, offset1, stride1, offset2, stride2); 161} 162 163static void 164drm_create_prime_buffer(struct wl_client *client, 165 struct wl_resource *resource, 166 uint32_t id, int fd, 167 int32_t width, int32_t height, uint32_t format, 168 int32_t offset0, int32_t stride0, 169 int32_t offset1, int32_t stride1, 170 int32_t offset2, int32_t stride2) 171{ 172 create_buffer(client, resource, id, 0, fd, width, height, format, 173 offset0, stride0, offset1, stride1, offset2, stride2); 174 close(fd); 175} 176 177static void 178drm_authenticate(struct wl_client *client, 179 struct wl_resource *resource, uint32_t id) 180{ 181 struct wl_drm *drm = wl_resource_get_user_data(resource); 182 183 if (!drm->callbacks.authenticate || 184 drm->callbacks.authenticate(drm->user_data, id) < 0) 185 wl_resource_post_error(resource, 186 WL_DRM_ERROR_AUTHENTICATE_FAIL, 187 "authenticate failed"); 188 else 189 wl_resource_post_event(resource, WL_DRM_AUTHENTICATED); 190} 191 192static const struct wl_drm_interface drm_interface = { 193 drm_authenticate, 194 drm_create_buffer, 195 drm_create_planar_buffer, 196 drm_create_prime_buffer 197}; 198 199static void 200bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id) 201{ 202 struct wl_drm *drm = data; 203 struct wl_resource *resource; 204 uint32_t capabilities; 205 206 resource = wl_resource_create(client, &wl_drm_interface, 207 MIN(version, 2), id); 208 if (!resource) { 209 wl_client_post_no_memory(client); 210 return; 211 } 212 213 wl_resource_set_implementation(resource, &drm_interface, data, NULL); 214 215 wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name); 216 217 if (drm->callbacks.is_format_supported(drm->user_data, 218 WL_DRM_FORMAT_ARGB2101010)) { 219 wl_resource_post_event(resource, WL_DRM_FORMAT, 220 WL_DRM_FORMAT_ARGB2101010); 221 } 222 223 if (drm->callbacks.is_format_supported(drm->user_data, 224 WL_DRM_FORMAT_XRGB2101010)) { 225 wl_resource_post_event(resource, WL_DRM_FORMAT, 226 WL_DRM_FORMAT_XRGB2101010); 227 } 228 229 if (drm->callbacks.is_format_supported(drm->user_data, 230 WL_DRM_FORMAT_ABGR2101010)) { 231 wl_resource_post_event(resource, WL_DRM_FORMAT, 232 WL_DRM_FORMAT_ABGR2101010); 233 } 234 235 if (drm->callbacks.is_format_supported(drm->user_data, 236 WL_DRM_FORMAT_XBGR2101010)) { 237 wl_resource_post_event(resource, WL_DRM_FORMAT, 238 WL_DRM_FORMAT_XBGR2101010); 239 } 240 241 wl_resource_post_event(resource, WL_DRM_FORMAT, 242 WL_DRM_FORMAT_ARGB8888); 243 wl_resource_post_event(resource, WL_DRM_FORMAT, 244 WL_DRM_FORMAT_XRGB8888); 245 wl_resource_post_event(resource, WL_DRM_FORMAT, 246 WL_DRM_FORMAT_RGB565); 247 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV410); 248 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV411); 249 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV420); 250 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV422); 251 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV444); 252 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12); 253 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16); 254 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV); 255 256 capabilities = 0; 257 if (drm->flags & WAYLAND_DRM_PRIME) 258 capabilities |= WL_DRM_CAPABILITY_PRIME; 259 260 if (version >= 2) 261 wl_resource_post_event(resource, WL_DRM_CAPABILITIES, capabilities); 262} 263 264struct wl_drm * 265wayland_drm_init(struct wl_display *display, char *device_name, 266 const struct wayland_drm_callbacks *callbacks, void *user_data, 267 uint32_t flags) 268{ 269 struct wl_drm *drm; 270 271 drm = malloc(sizeof *drm); 272 if (!drm) 273 return NULL; 274 275 drm->display = display; 276 drm->device_name = strdup(device_name); 277 drm->callbacks = *callbacks; 278 drm->user_data = user_data; 279 drm->flags = flags; 280 281 drm->buffer_interface.destroy = buffer_destroy; 282 283 drm->wl_drm_global = 284 wl_global_create(display, &wl_drm_interface, 2, 285 drm, bind_drm); 286 287 return drm; 288} 289 290void 291wayland_drm_uninit(struct wl_drm *drm) 292{ 293 free(drm->device_name); 294 295 wl_global_destroy(drm->wl_drm_global); 296 297 free(drm); 298} 299