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