13464ebd5Sriastradh/* 23464ebd5Sriastradh * Copyright © 2011 Kristian Høgsberg 33464ebd5Sriastradh * Copyright © 2011 Benjamin Franzke 43464ebd5Sriastradh * 53464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 63464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"), 73464ebd5Sriastradh * to deal in the Software without restriction, including without limitation 83464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 93464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the 103464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions: 113464ebd5Sriastradh * 123464ebd5Sriastradh * The above copyright notice and this permission notice (including the next 133464ebd5Sriastradh * paragraph) shall be included in all copies or substantial portions of the 143464ebd5Sriastradh * Software. 153464ebd5Sriastradh * 163464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 173464ebd5Sriastradh * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 183464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 193464ebd5Sriastradh * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 203464ebd5Sriastradh * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 213464ebd5Sriastradh * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 223464ebd5Sriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 233464ebd5Sriastradh * DEALINGS IN THE SOFTWARE. 243464ebd5Sriastradh * 253464ebd5Sriastradh * Authors: 263464ebd5Sriastradh * Kristian Høgsberg <krh@bitplanet.net> 273464ebd5Sriastradh * Benjamin Franzke <benjaminfranzke@googlemail.com> 283464ebd5Sriastradh */ 293464ebd5Sriastradh 303464ebd5Sriastradh#include <stdio.h> 313464ebd5Sriastradh#include <stdlib.h> 323464ebd5Sriastradh#include <string.h> 333464ebd5Sriastradh#include <stddef.h> 34af69d88dSmrg#include <unistd.h> 353464ebd5Sriastradh 363464ebd5Sriastradh#include <wayland-server.h> 373464ebd5Sriastradh#include "wayland-drm.h" 383464ebd5Sriastradh#include "wayland-drm-server-protocol.h" 393464ebd5Sriastradh 40af69d88dSmrg#define MIN(x,y) (((x)<(y))?(x):(y)) 41af69d88dSmrg 423464ebd5Sriastradhstatic void 43af69d88dSmrgdestroy_buffer(struct wl_resource *resource) 443464ebd5Sriastradh{ 4501e04c3fSmrg struct wl_drm_buffer *buffer = wl_resource_get_user_data(resource); 463464ebd5Sriastradh struct wl_drm *drm = buffer->drm; 473464ebd5Sriastradh 4801e04c3fSmrg drm->callbacks.release_buffer(drm->user_data, buffer); 493464ebd5Sriastradh free(buffer); 503464ebd5Sriastradh} 513464ebd5Sriastradh 523464ebd5Sriastradhstatic void 53af69d88dSmrgbuffer_destroy(struct wl_client *client, struct wl_resource *resource) 543464ebd5Sriastradh{ 55af69d88dSmrg wl_resource_destroy(resource); 563464ebd5Sriastradh} 573464ebd5Sriastradh 583464ebd5Sriastradhstatic void 59af69d88dSmrgcreate_buffer(struct wl_client *client, struct wl_resource *resource, 60af69d88dSmrg uint32_t id, uint32_t name, int fd, 61af69d88dSmrg int32_t width, int32_t height, 62af69d88dSmrg uint32_t format, 63af69d88dSmrg int32_t offset0, int32_t stride0, 64af69d88dSmrg int32_t offset1, int32_t stride1, 65af69d88dSmrg int32_t offset2, int32_t stride2) 663464ebd5Sriastradh{ 6701e04c3fSmrg struct wl_drm *drm = wl_resource_get_user_data(resource); 683464ebd5Sriastradh struct wl_drm_buffer *buffer; 693464ebd5Sriastradh 703464ebd5Sriastradh buffer = calloc(1, sizeof *buffer); 713464ebd5Sriastradh if (buffer == NULL) { 72af69d88dSmrg wl_resource_post_no_memory(resource); 733464ebd5Sriastradh return; 743464ebd5Sriastradh } 753464ebd5Sriastradh 763464ebd5Sriastradh buffer->drm = drm; 77af69d88dSmrg buffer->width = width; 78af69d88dSmrg buffer->height = height; 79af69d88dSmrg buffer->format = format; 80af69d88dSmrg buffer->offset[0] = offset0; 81af69d88dSmrg buffer->stride[0] = stride0; 82af69d88dSmrg buffer->offset[1] = offset1; 83af69d88dSmrg buffer->stride[1] = stride1; 84af69d88dSmrg buffer->offset[2] = offset2; 85af69d88dSmrg buffer->stride[2] = stride2; 86af69d88dSmrg 8701e04c3fSmrg drm->callbacks.reference_buffer(drm->user_data, name, fd, buffer); 88af69d88dSmrg if (buffer->driver_buffer == NULL) { 89af69d88dSmrg wl_resource_post_error(resource, 90af69d88dSmrg WL_DRM_ERROR_INVALID_NAME, 91af69d88dSmrg "invalid name"); 923464ebd5Sriastradh return; 933464ebd5Sriastradh } 943464ebd5Sriastradh 95af69d88dSmrg buffer->resource = 96af69d88dSmrg wl_resource_create(client, &wl_buffer_interface, 1, id); 97af69d88dSmrg if (!buffer->resource) { 98af69d88dSmrg wl_resource_post_no_memory(resource); 99af69d88dSmrg free(buffer); 1003464ebd5Sriastradh return; 1013464ebd5Sriastradh } 1023464ebd5Sriastradh 103af69d88dSmrg wl_resource_set_implementation(buffer->resource, 104af69d88dSmrg (void (**)(void)) &drm->buffer_interface, 105af69d88dSmrg buffer, destroy_buffer); 106af69d88dSmrg} 1073464ebd5Sriastradh 108af69d88dSmrgstatic void 109af69d88dSmrgdrm_create_buffer(struct wl_client *client, struct wl_resource *resource, 110af69d88dSmrg uint32_t id, uint32_t name, int32_t width, int32_t height, 111af69d88dSmrg uint32_t stride, uint32_t format) 112af69d88dSmrg{ 113af69d88dSmrg switch (format) { 11401e04c3fSmrg case WL_DRM_FORMAT_ABGR2101010: 11501e04c3fSmrg case WL_DRM_FORMAT_XBGR2101010: 11601e04c3fSmrg case WL_DRM_FORMAT_ARGB2101010: 11701e04c3fSmrg case WL_DRM_FORMAT_XRGB2101010: 118af69d88dSmrg case WL_DRM_FORMAT_ARGB8888: 119af69d88dSmrg case WL_DRM_FORMAT_XRGB8888: 120af69d88dSmrg case WL_DRM_FORMAT_YUYV: 121af69d88dSmrg case WL_DRM_FORMAT_RGB565: 122af69d88dSmrg break; 123af69d88dSmrg default: 124af69d88dSmrg wl_resource_post_error(resource, 125af69d88dSmrg WL_DRM_ERROR_INVALID_FORMAT, 126af69d88dSmrg "invalid format"); 127af69d88dSmrg return; 128af69d88dSmrg } 129af69d88dSmrg 130af69d88dSmrg create_buffer(client, resource, id, 131af69d88dSmrg name, -1, width, height, format, 0, stride, 0, 0, 0, 0); 132af69d88dSmrg} 1333464ebd5Sriastradh 134af69d88dSmrgstatic void 135af69d88dSmrgdrm_create_planar_buffer(struct wl_client *client, 136af69d88dSmrg struct wl_resource *resource, 137af69d88dSmrg uint32_t id, uint32_t name, 138af69d88dSmrg int32_t width, int32_t height, uint32_t format, 139af69d88dSmrg int32_t offset0, int32_t stride0, 140af69d88dSmrg int32_t offset1, int32_t stride1, 141af69d88dSmrg int32_t offset2, int32_t stride2) 142af69d88dSmrg{ 143af69d88dSmrg switch (format) { 144af69d88dSmrg case WL_DRM_FORMAT_YUV410: 145af69d88dSmrg case WL_DRM_FORMAT_YUV411: 146af69d88dSmrg case WL_DRM_FORMAT_YUV420: 147af69d88dSmrg case WL_DRM_FORMAT_YUV422: 148af69d88dSmrg case WL_DRM_FORMAT_YUV444: 149af69d88dSmrg case WL_DRM_FORMAT_NV12: 150af69d88dSmrg case WL_DRM_FORMAT_NV16: 151af69d88dSmrg break; 152af69d88dSmrg default: 153af69d88dSmrg wl_resource_post_error(resource, 154af69d88dSmrg WL_DRM_ERROR_INVALID_FORMAT, 155af69d88dSmrg "invalid format"); 156af69d88dSmrg return; 157af69d88dSmrg } 158af69d88dSmrg 159af69d88dSmrg create_buffer(client, resource, id, name, -1, width, height, format, 160af69d88dSmrg offset0, stride0, offset1, stride1, offset2, stride2); 161af69d88dSmrg} 162af69d88dSmrg 163af69d88dSmrgstatic void 164af69d88dSmrgdrm_create_prime_buffer(struct wl_client *client, 165af69d88dSmrg struct wl_resource *resource, 166af69d88dSmrg uint32_t id, int fd, 167af69d88dSmrg int32_t width, int32_t height, uint32_t format, 168af69d88dSmrg int32_t offset0, int32_t stride0, 169af69d88dSmrg int32_t offset1, int32_t stride1, 170af69d88dSmrg int32_t offset2, int32_t stride2) 171af69d88dSmrg{ 172af69d88dSmrg create_buffer(client, resource, id, 0, fd, width, height, format, 173af69d88dSmrg offset0, stride0, offset1, stride1, offset2, stride2); 174af69d88dSmrg close(fd); 1753464ebd5Sriastradh} 1763464ebd5Sriastradh 1773464ebd5Sriastradhstatic void 1783464ebd5Sriastradhdrm_authenticate(struct wl_client *client, 179af69d88dSmrg struct wl_resource *resource, uint32_t id) 1803464ebd5Sriastradh{ 18101e04c3fSmrg struct wl_drm *drm = wl_resource_get_user_data(resource); 182af69d88dSmrg 1837ec681f3Smrg if (!drm->callbacks.authenticate || 1847ec681f3Smrg drm->callbacks.authenticate(drm->user_data, id) < 0) 185af69d88dSmrg wl_resource_post_error(resource, 186af69d88dSmrg WL_DRM_ERROR_AUTHENTICATE_FAIL, 1877ec681f3Smrg "authenticate failed"); 1883464ebd5Sriastradh else 189af69d88dSmrg wl_resource_post_event(resource, WL_DRM_AUTHENTICATED); 1903464ebd5Sriastradh} 1913464ebd5Sriastradh 19201e04c3fSmrgstatic const struct wl_drm_interface drm_interface = { 1933464ebd5Sriastradh drm_authenticate, 194af69d88dSmrg drm_create_buffer, 195af69d88dSmrg drm_create_planar_buffer, 196af69d88dSmrg drm_create_prime_buffer 1973464ebd5Sriastradh}; 1983464ebd5Sriastradh 1993464ebd5Sriastradhstatic void 200af69d88dSmrgbind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id) 2013464ebd5Sriastradh{ 202af69d88dSmrg struct wl_drm *drm = data; 203af69d88dSmrg struct wl_resource *resource; 204af69d88dSmrg uint32_t capabilities; 2053464ebd5Sriastradh 206af69d88dSmrg resource = wl_resource_create(client, &wl_drm_interface, 207af69d88dSmrg MIN(version, 2), id); 208af69d88dSmrg if (!resource) { 209af69d88dSmrg wl_client_post_no_memory(client); 210af69d88dSmrg return; 211af69d88dSmrg } 212af69d88dSmrg 213af69d88dSmrg wl_resource_set_implementation(resource, &drm_interface, data, NULL); 214af69d88dSmrg 215af69d88dSmrg wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name); 21601e04c3fSmrg 21701e04c3fSmrg if (drm->callbacks.is_format_supported(drm->user_data, 21801e04c3fSmrg WL_DRM_FORMAT_ARGB2101010)) { 21901e04c3fSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, 22001e04c3fSmrg WL_DRM_FORMAT_ARGB2101010); 22101e04c3fSmrg } 22201e04c3fSmrg 22301e04c3fSmrg if (drm->callbacks.is_format_supported(drm->user_data, 22401e04c3fSmrg WL_DRM_FORMAT_XRGB2101010)) { 22501e04c3fSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, 22601e04c3fSmrg WL_DRM_FORMAT_XRGB2101010); 22701e04c3fSmrg } 22801e04c3fSmrg 22901e04c3fSmrg if (drm->callbacks.is_format_supported(drm->user_data, 23001e04c3fSmrg WL_DRM_FORMAT_ABGR2101010)) { 23101e04c3fSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, 23201e04c3fSmrg WL_DRM_FORMAT_ABGR2101010); 23301e04c3fSmrg } 23401e04c3fSmrg 23501e04c3fSmrg if (drm->callbacks.is_format_supported(drm->user_data, 23601e04c3fSmrg WL_DRM_FORMAT_XBGR2101010)) { 23701e04c3fSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, 23801e04c3fSmrg WL_DRM_FORMAT_XBGR2101010); 23901e04c3fSmrg } 24001e04c3fSmrg 241af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, 242af69d88dSmrg WL_DRM_FORMAT_ARGB8888); 243af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, 244af69d88dSmrg WL_DRM_FORMAT_XRGB8888); 245af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, 246af69d88dSmrg WL_DRM_FORMAT_RGB565); 247af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV410); 248af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV411); 249af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV420); 250af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV422); 251af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV444); 252af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12); 253af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16); 254af69d88dSmrg wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV); 255af69d88dSmrg 256af69d88dSmrg capabilities = 0; 257af69d88dSmrg if (drm->flags & WAYLAND_DRM_PRIME) 258af69d88dSmrg capabilities |= WL_DRM_CAPABILITY_PRIME; 259af69d88dSmrg 260af69d88dSmrg if (version >= 2) 261af69d88dSmrg wl_resource_post_event(resource, WL_DRM_CAPABILITIES, capabilities); 262af69d88dSmrg} 263af69d88dSmrg 2643464ebd5Sriastradhstruct wl_drm * 2653464ebd5Sriastradhwayland_drm_init(struct wl_display *display, char *device_name, 26601e04c3fSmrg const struct wayland_drm_callbacks *callbacks, void *user_data, 267af69d88dSmrg uint32_t flags) 2683464ebd5Sriastradh{ 2693464ebd5Sriastradh struct wl_drm *drm; 2703464ebd5Sriastradh 2713464ebd5Sriastradh drm = malloc(sizeof *drm); 27201e04c3fSmrg if (!drm) 27301e04c3fSmrg return NULL; 2743464ebd5Sriastradh 2753464ebd5Sriastradh drm->display = display; 2763464ebd5Sriastradh drm->device_name = strdup(device_name); 27701e04c3fSmrg drm->callbacks = *callbacks; 2783464ebd5Sriastradh drm->user_data = user_data; 279af69d88dSmrg drm->flags = flags; 2803464ebd5Sriastradh 281af69d88dSmrg drm->buffer_interface.destroy = buffer_destroy; 282af69d88dSmrg 283af69d88dSmrg drm->wl_drm_global = 284af69d88dSmrg wl_global_create(display, &wl_drm_interface, 2, 285af69d88dSmrg drm, bind_drm); 2863464ebd5Sriastradh 2873464ebd5Sriastradh return drm; 2883464ebd5Sriastradh} 2893464ebd5Sriastradh 2903464ebd5Sriastradhvoid 2913464ebd5Sriastradhwayland_drm_uninit(struct wl_drm *drm) 2923464ebd5Sriastradh{ 2933464ebd5Sriastradh free(drm->device_name); 2943464ebd5Sriastradh 295af69d88dSmrg wl_global_destroy(drm->wl_drm_global); 2963464ebd5Sriastradh 2973464ebd5Sriastradh free(drm); 2983464ebd5Sriastradh} 299