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 42struct wl_drm { 43 struct wl_display *display; 44 struct wl_global *wl_drm_global; 45 46 void *user_data; 47 char *device_name; 48 uint32_t flags; 49 50 struct wayland_drm_callbacks *callbacks; 51 52 struct wl_buffer_interface buffer_interface; 53}; 54 55static void 56destroy_buffer(struct wl_resource *resource) 57{ 58 struct wl_drm_buffer *buffer = resource->data; 59 struct wl_drm *drm = buffer->drm; 60 61 drm->callbacks->release_buffer(drm->user_data, buffer); 62 free(buffer); 63} 64 65static void 66buffer_destroy(struct wl_client *client, struct wl_resource *resource) 67{ 68 wl_resource_destroy(resource); 69} 70 71static void 72create_buffer(struct wl_client *client, struct wl_resource *resource, 73 uint32_t id, uint32_t name, int fd, 74 int32_t width, int32_t height, 75 uint32_t format, 76 int32_t offset0, int32_t stride0, 77 int32_t offset1, int32_t stride1, 78 int32_t offset2, int32_t stride2) 79{ 80 struct wl_drm *drm = resource->data; 81 struct wl_drm_buffer *buffer; 82 83 buffer = calloc(1, sizeof *buffer); 84 if (buffer == NULL) { 85 wl_resource_post_no_memory(resource); 86 return; 87 } 88 89 buffer->drm = drm; 90 buffer->width = width; 91 buffer->height = height; 92 buffer->format = format; 93 buffer->offset[0] = offset0; 94 buffer->stride[0] = stride0; 95 buffer->offset[1] = offset1; 96 buffer->stride[1] = stride1; 97 buffer->offset[2] = offset2; 98 buffer->stride[2] = stride2; 99 100 drm->callbacks->reference_buffer(drm->user_data, name, fd, buffer); 101 if (buffer->driver_buffer == NULL) { 102 wl_resource_post_error(resource, 103 WL_DRM_ERROR_INVALID_NAME, 104 "invalid name"); 105 return; 106 } 107 108 buffer->resource = 109 wl_resource_create(client, &wl_buffer_interface, 1, id); 110 if (!buffer->resource) { 111 wl_resource_post_no_memory(resource); 112 free(buffer); 113 return; 114 } 115 116 wl_resource_set_implementation(buffer->resource, 117 (void (**)(void)) &drm->buffer_interface, 118 buffer, destroy_buffer); 119} 120 121static void 122drm_create_buffer(struct wl_client *client, struct wl_resource *resource, 123 uint32_t id, uint32_t name, int32_t width, int32_t height, 124 uint32_t stride, uint32_t format) 125{ 126 switch (format) { 127 case WL_DRM_FORMAT_ARGB8888: 128 case WL_DRM_FORMAT_XRGB8888: 129 case WL_DRM_FORMAT_YUYV: 130 case WL_DRM_FORMAT_RGB565: 131 break; 132 default: 133 wl_resource_post_error(resource, 134 WL_DRM_ERROR_INVALID_FORMAT, 135 "invalid format"); 136 return; 137 } 138 139 create_buffer(client, resource, id, 140 name, -1, width, height, format, 0, stride, 0, 0, 0, 0); 141} 142 143static void 144drm_create_planar_buffer(struct wl_client *client, 145 struct wl_resource *resource, 146 uint32_t id, uint32_t name, 147 int32_t width, int32_t height, uint32_t format, 148 int32_t offset0, int32_t stride0, 149 int32_t offset1, int32_t stride1, 150 int32_t offset2, int32_t stride2) 151{ 152 switch (format) { 153 case WL_DRM_FORMAT_YUV410: 154 case WL_DRM_FORMAT_YUV411: 155 case WL_DRM_FORMAT_YUV420: 156 case WL_DRM_FORMAT_YUV422: 157 case WL_DRM_FORMAT_YUV444: 158 case WL_DRM_FORMAT_NV12: 159 case WL_DRM_FORMAT_NV16: 160 break; 161 default: 162 wl_resource_post_error(resource, 163 WL_DRM_ERROR_INVALID_FORMAT, 164 "invalid format"); 165 return; 166 } 167 168 create_buffer(client, resource, id, name, -1, width, height, format, 169 offset0, stride0, offset1, stride1, offset2, stride2); 170} 171 172static void 173drm_create_prime_buffer(struct wl_client *client, 174 struct wl_resource *resource, 175 uint32_t id, int fd, 176 int32_t width, int32_t height, uint32_t format, 177 int32_t offset0, int32_t stride0, 178 int32_t offset1, int32_t stride1, 179 int32_t offset2, int32_t stride2) 180{ 181 create_buffer(client, resource, id, 0, fd, width, height, format, 182 offset0, stride0, offset1, stride1, offset2, stride2); 183 close(fd); 184} 185 186static void 187drm_authenticate(struct wl_client *client, 188 struct wl_resource *resource, uint32_t id) 189{ 190 struct wl_drm *drm = resource->data; 191 192 if (drm->callbacks->authenticate(drm->user_data, id) < 0) 193 wl_resource_post_error(resource, 194 WL_DRM_ERROR_AUTHENTICATE_FAIL, 195 "authenicate failed"); 196 else 197 wl_resource_post_event(resource, WL_DRM_AUTHENTICATED); 198} 199 200static const struct wl_drm_interface drm_interface = { 201 drm_authenticate, 202 drm_create_buffer, 203 drm_create_planar_buffer, 204 drm_create_prime_buffer 205}; 206 207static void 208bind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id) 209{ 210 struct wl_drm *drm = data; 211 struct wl_resource *resource; 212 uint32_t capabilities; 213 214 resource = wl_resource_create(client, &wl_drm_interface, 215 MIN(version, 2), id); 216 if (!resource) { 217 wl_client_post_no_memory(client); 218 return; 219 } 220 221 wl_resource_set_implementation(resource, &drm_interface, data, NULL); 222 223 wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name); 224 wl_resource_post_event(resource, WL_DRM_FORMAT, 225 WL_DRM_FORMAT_ARGB8888); 226 wl_resource_post_event(resource, WL_DRM_FORMAT, 227 WL_DRM_FORMAT_XRGB8888); 228 wl_resource_post_event(resource, WL_DRM_FORMAT, 229 WL_DRM_FORMAT_RGB565); 230 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV410); 231 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV411); 232 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV420); 233 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV422); 234 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV444); 235 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12); 236 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16); 237 wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV); 238 239 capabilities = 0; 240 if (drm->flags & WAYLAND_DRM_PRIME) 241 capabilities |= WL_DRM_CAPABILITY_PRIME; 242 243 if (version >= 2) 244 wl_resource_post_event(resource, WL_DRM_CAPABILITIES, capabilities); 245} 246 247struct wl_drm_buffer * 248wayland_drm_buffer_get(struct wl_drm *drm, struct wl_resource *resource) 249{ 250 if (resource == NULL) 251 return NULL; 252 253 if (wl_resource_instance_of(resource, &wl_buffer_interface, 254 &drm->buffer_interface)) 255 return wl_resource_get_user_data(resource); 256 else 257 return NULL; 258} 259 260struct wl_drm * 261wayland_drm_init(struct wl_display *display, char *device_name, 262 struct wayland_drm_callbacks *callbacks, void *user_data, 263 uint32_t flags) 264{ 265 struct wl_drm *drm; 266 267 drm = malloc(sizeof *drm); 268 if (!drm) 269 return NULL; 270 271 drm->display = display; 272 drm->device_name = strdup(device_name); 273 drm->callbacks = callbacks; 274 drm->user_data = user_data; 275 drm->flags = flags; 276 277 drm->buffer_interface.destroy = buffer_destroy; 278 279 drm->wl_drm_global = 280 wl_global_create(display, &wl_drm_interface, 2, 281 drm, bind_drm); 282 283 return drm; 284} 285 286void 287wayland_drm_uninit(struct wl_drm *drm) 288{ 289 free(drm->device_name); 290 291 wl_global_destroy(drm->wl_drm_global); 292 293 free(drm); 294} 295 296uint32_t 297wayland_drm_buffer_get_format(struct wl_drm_buffer *buffer) 298{ 299 return buffer->format; 300} 301 302void * 303wayland_drm_buffer_get_buffer(struct wl_drm_buffer *buffer) 304{ 305 return buffer->driver_buffer; 306} 307