1 /* 2 * Copyright 2011 Kristian Hgsberg 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 Hgsberg <krh (at) bitplanet.net> 27 * Benjamin Franzke <benjaminfranzke (at) 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 42 static void 43 destroy_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 52 static void 53 buffer_destroy(struct wl_client *client, struct wl_resource *resource) 54 { 55 wl_resource_destroy(resource); 56 } 57 58 static void 59 create_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 108 static void 109 drm_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_ARGB2101010: 115 case WL_DRM_FORMAT_XRGB2101010: 116 case WL_DRM_FORMAT_ARGB8888: 117 case WL_DRM_FORMAT_XRGB8888: 118 case WL_DRM_FORMAT_YUYV: 119 case WL_DRM_FORMAT_RGB565: 120 break; 121 default: 122 wl_resource_post_error(resource, 123 WL_DRM_ERROR_INVALID_FORMAT, 124 "invalid format"); 125 return; 126 } 127 128 create_buffer(client, resource, id, 129 name, -1, width, height, format, 0, stride, 0, 0, 0, 0); 130 } 131 132 static void 133 drm_create_planar_buffer(struct wl_client *client, 134 struct wl_resource *resource, 135 uint32_t id, uint32_t name, 136 int32_t width, int32_t height, uint32_t format, 137 int32_t offset0, int32_t stride0, 138 int32_t offset1, int32_t stride1, 139 int32_t offset2, int32_t stride2) 140 { 141 switch (format) { 142 case WL_DRM_FORMAT_YUV410: 143 case WL_DRM_FORMAT_YUV411: 144 case WL_DRM_FORMAT_YUV420: 145 case WL_DRM_FORMAT_YUV422: 146 case WL_DRM_FORMAT_YUV444: 147 case WL_DRM_FORMAT_NV12: 148 case WL_DRM_FORMAT_NV16: 149 break; 150 default: 151 wl_resource_post_error(resource, 152 WL_DRM_ERROR_INVALID_FORMAT, 153 "invalid format"); 154 return; 155 } 156 157 create_buffer(client, resource, id, name, -1, width, height, format, 158 offset0, stride0, offset1, stride1, offset2, stride2); 159 } 160 161 static void 162 drm_create_prime_buffer(struct wl_client *client, 163 struct wl_resource *resource, 164 uint32_t id, int fd, 165 int32_t width, int32_t height, uint32_t format, 166 int32_t offset0, int32_t stride0, 167 int32_t offset1, int32_t stride1, 168 int32_t offset2, int32_t stride2) 169 { 170 create_buffer(client, resource, id, 0, fd, width, height, format, 171 offset0, stride0, offset1, stride1, offset2, stride2); 172 close(fd); 173 } 174 175 static void 176 drm_authenticate(struct wl_client *client, 177 struct wl_resource *resource, uint32_t id) 178 { 179 struct wl_drm *drm = wl_resource_get_user_data(resource); 180 181 if (drm->callbacks.authenticate(drm->user_data, id) < 0) 182 wl_resource_post_error(resource, 183 WL_DRM_ERROR_AUTHENTICATE_FAIL, 184 "authenicate failed"); 185 else 186 wl_resource_post_event(resource, WL_DRM_AUTHENTICATED); 187 } 188 189 static const struct wl_drm_interface drm_interface = { 190 drm_authenticate, 191 drm_create_buffer, 192 drm_create_planar_buffer, 193 drm_create_prime_buffer 194 }; 195 196 static void 197 bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id) 198 { 199 struct wl_drm *drm = data; 200 struct wl_resource *resource; 201 uint32_t capabilities; 202 203 resource = wl_resource_create(client, &wl_drm_interface, 204 MIN(version, 2), id); 205 if (!resource) { 206 wl_client_post_no_memory(client); 207 return; 208 } 209 210 wl_resource_set_implementation(resource, &drm_interface, data, NULL); 211 212 wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name); 213 wl_resource_post_event(resource, WL_DRM_FORMAT, 214 WL_DRM_FORMAT_ARGB2101010); 215 wl_resource_post_event(resource, WL_DRM_FORMAT, 216 WL_DRM_FORMAT_XRGB2101010); 217 wl_resource_post_event(resource, WL_DRM_FORMAT, 218 WL_DRM_FORMAT_ARGB8888); 219 wl_resource_post_event(resource, WL_DRM_FORMAT, 220 WL_DRM_FORMAT_XRGB8888); 221 wl_resource_post_event(resource, WL_DRM_FORMAT, 222 WL_DRM_FORMAT_RGB565); 223 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV410); 224 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV411); 225 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV420); 226 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV422); 227 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV444); 228 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12); 229 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16); 230 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV); 231 232 capabilities = 0; 233 if (drm->flags & WAYLAND_DRM_PRIME) 234 capabilities |= WL_DRM_CAPABILITY_PRIME; 235 236 if (version >= 2) 237 wl_resource_post_event(resource, WL_DRM_CAPABILITIES, capabilities); 238 } 239 240 struct wl_drm * 241 wayland_drm_init(struct wl_display *display, char *device_name, 242 const struct wayland_drm_callbacks *callbacks, void *user_data, 243 uint32_t flags) 244 { 245 struct wl_drm *drm; 246 247 drm = malloc(sizeof *drm); 248 if (!drm) 249 return NULL; 250 251 drm->display = display; 252 drm->device_name = strdup(device_name); 253 drm->callbacks = *callbacks; 254 drm->user_data = user_data; 255 drm->flags = flags; 256 257 drm->buffer_interface.destroy = buffer_destroy; 258 259 drm->wl_drm_global = 260 wl_global_create(display, &wl_drm_interface, 2, 261 drm, bind_drm); 262 263 return drm; 264 } 265 266 void 267 wayland_drm_uninit(struct wl_drm *drm) 268 { 269 free(drm->device_name); 270 271 wl_global_destroy(drm->wl_drm_global); 272 273 free(drm); 274 } 275