1848b8605Smrg/*
2848b8605Smrg * Copyright © 2011 Kristian Høgsberg
3848b8605Smrg * Copyright © 2011 Benjamin Franzke
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the "Software"),
7848b8605Smrg * to deal in the Software without restriction, including without limitation
8848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
10848b8605Smrg * Software is furnished to do so, subject to the following conditions:
11848b8605Smrg *
12848b8605Smrg * The above copyright notice and this permission notice (including the next
13848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
14848b8605Smrg * Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17848b8605Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19848b8605Smrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20848b8605Smrg * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21848b8605Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22848b8605Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23848b8605Smrg * DEALINGS IN THE SOFTWARE.
24848b8605Smrg *
25848b8605Smrg * Authors:
26848b8605Smrg *    Kristian Høgsberg <krh@bitplanet.net>
27848b8605Smrg *    Benjamin Franzke <benjaminfranzke@googlemail.com>
28848b8605Smrg */
29848b8605Smrg
30848b8605Smrg#include <stdio.h>
31848b8605Smrg#include <stdlib.h>
32848b8605Smrg#include <string.h>
33848b8605Smrg#include <stddef.h>
34848b8605Smrg#include <unistd.h>
35848b8605Smrg
36848b8605Smrg#include <wayland-server.h>
37848b8605Smrg#include "wayland-drm.h"
38848b8605Smrg#include "wayland-drm-server-protocol.h"
39848b8605Smrg
40848b8605Smrg#define MIN(x,y) (((x)<(y))?(x):(y))
41848b8605Smrg
42848b8605Smrgstatic void
43848b8605Smrgdestroy_buffer(struct wl_resource *resource)
44848b8605Smrg{
45b8e80941Smrg	struct wl_drm_buffer *buffer = wl_resource_get_user_data(resource);
46848b8605Smrg	struct wl_drm *drm = buffer->drm;
47848b8605Smrg
48b8e80941Smrg	drm->callbacks.release_buffer(drm->user_data, buffer);
49848b8605Smrg	free(buffer);
50848b8605Smrg}
51848b8605Smrg
52848b8605Smrgstatic void
53848b8605Smrgbuffer_destroy(struct wl_client *client, struct wl_resource *resource)
54848b8605Smrg{
55848b8605Smrg	wl_resource_destroy(resource);
56848b8605Smrg}
57848b8605Smrg
58848b8605Smrgstatic void
59848b8605Smrgcreate_buffer(struct wl_client *client, struct wl_resource *resource,
60848b8605Smrg              uint32_t id, uint32_t name, int fd,
61848b8605Smrg              int32_t width, int32_t height,
62848b8605Smrg              uint32_t format,
63848b8605Smrg              int32_t offset0, int32_t stride0,
64848b8605Smrg              int32_t offset1, int32_t stride1,
65848b8605Smrg              int32_t offset2, int32_t stride2)
66848b8605Smrg{
67b8e80941Smrg	struct wl_drm *drm = wl_resource_get_user_data(resource);
68848b8605Smrg	struct wl_drm_buffer *buffer;
69848b8605Smrg
70848b8605Smrg	buffer = calloc(1, sizeof *buffer);
71848b8605Smrg	if (buffer == NULL) {
72848b8605Smrg		wl_resource_post_no_memory(resource);
73848b8605Smrg		return;
74848b8605Smrg	}
75848b8605Smrg
76848b8605Smrg	buffer->drm = drm;
77848b8605Smrg	buffer->width = width;
78848b8605Smrg	buffer->height = height;
79848b8605Smrg	buffer->format = format;
80848b8605Smrg	buffer->offset[0] = offset0;
81848b8605Smrg	buffer->stride[0] = stride0;
82848b8605Smrg	buffer->offset[1] = offset1;
83848b8605Smrg	buffer->stride[1] = stride1;
84848b8605Smrg	buffer->offset[2] = offset2;
85848b8605Smrg	buffer->stride[2] = stride2;
86848b8605Smrg
87b8e80941Smrg        drm->callbacks.reference_buffer(drm->user_data, name, fd, buffer);
88848b8605Smrg	if (buffer->driver_buffer == NULL) {
89848b8605Smrg		wl_resource_post_error(resource,
90848b8605Smrg				       WL_DRM_ERROR_INVALID_NAME,
91848b8605Smrg				       "invalid name");
92848b8605Smrg		return;
93848b8605Smrg	}
94848b8605Smrg
95848b8605Smrg	buffer->resource =
96848b8605Smrg		wl_resource_create(client, &wl_buffer_interface, 1, id);
97848b8605Smrg	if (!buffer->resource) {
98848b8605Smrg		wl_resource_post_no_memory(resource);
99848b8605Smrg		free(buffer);
100848b8605Smrg		return;
101848b8605Smrg	}
102848b8605Smrg
103848b8605Smrg	wl_resource_set_implementation(buffer->resource,
104848b8605Smrg				       (void (**)(void)) &drm->buffer_interface,
105848b8605Smrg				       buffer, destroy_buffer);
106848b8605Smrg}
107848b8605Smrg
108848b8605Smrgstatic void
109848b8605Smrgdrm_create_buffer(struct wl_client *client, struct wl_resource *resource,
110848b8605Smrg		  uint32_t id, uint32_t name, int32_t width, int32_t height,
111848b8605Smrg		  uint32_t stride, uint32_t format)
112848b8605Smrg{
113848b8605Smrg        switch (format) {
114b8e80941Smrg        case WL_DRM_FORMAT_ABGR2101010:
115b8e80941Smrg        case WL_DRM_FORMAT_XBGR2101010:
116b8e80941Smrg        case WL_DRM_FORMAT_ARGB2101010:
117b8e80941Smrg        case WL_DRM_FORMAT_XRGB2101010:
118848b8605Smrg        case WL_DRM_FORMAT_ARGB8888:
119848b8605Smrg        case WL_DRM_FORMAT_XRGB8888:
120848b8605Smrg        case WL_DRM_FORMAT_YUYV:
121848b8605Smrg        case WL_DRM_FORMAT_RGB565:
122848b8605Smrg                break;
123848b8605Smrg        default:
124848b8605Smrg                wl_resource_post_error(resource,
125848b8605Smrg                                       WL_DRM_ERROR_INVALID_FORMAT,
126848b8605Smrg                                       "invalid format");
127848b8605Smrg           return;
128848b8605Smrg        }
129848b8605Smrg
130848b8605Smrg        create_buffer(client, resource, id,
131848b8605Smrg                      name, -1, width, height, format, 0, stride, 0, 0, 0, 0);
132848b8605Smrg}
133848b8605Smrg
134848b8605Smrgstatic void
135848b8605Smrgdrm_create_planar_buffer(struct wl_client *client,
136848b8605Smrg                         struct wl_resource *resource,
137848b8605Smrg                         uint32_t id, uint32_t name,
138848b8605Smrg                         int32_t width, int32_t height, uint32_t format,
139848b8605Smrg                         int32_t offset0, int32_t stride0,
140848b8605Smrg                         int32_t offset1, int32_t stride1,
141848b8605Smrg                         int32_t offset2, int32_t stride2)
142848b8605Smrg{
143848b8605Smrg        switch (format) {
144848b8605Smrg	case WL_DRM_FORMAT_YUV410:
145848b8605Smrg	case WL_DRM_FORMAT_YUV411:
146848b8605Smrg	case WL_DRM_FORMAT_YUV420:
147848b8605Smrg	case WL_DRM_FORMAT_YUV422:
148848b8605Smrg	case WL_DRM_FORMAT_YUV444:
149848b8605Smrg	case WL_DRM_FORMAT_NV12:
150848b8605Smrg        case WL_DRM_FORMAT_NV16:
151848b8605Smrg                break;
152848b8605Smrg        default:
153848b8605Smrg                wl_resource_post_error(resource,
154848b8605Smrg                                       WL_DRM_ERROR_INVALID_FORMAT,
155848b8605Smrg                                       "invalid format");
156848b8605Smrg           return;
157848b8605Smrg        }
158848b8605Smrg
159848b8605Smrg        create_buffer(client, resource, id, name, -1, width, height, format,
160848b8605Smrg                      offset0, stride0, offset1, stride1, offset2, stride2);
161848b8605Smrg}
162848b8605Smrg
163848b8605Smrgstatic void
164848b8605Smrgdrm_create_prime_buffer(struct wl_client *client,
165848b8605Smrg                        struct wl_resource *resource,
166848b8605Smrg                        uint32_t id, int fd,
167848b8605Smrg                        int32_t width, int32_t height, uint32_t format,
168848b8605Smrg                        int32_t offset0, int32_t stride0,
169848b8605Smrg                        int32_t offset1, int32_t stride1,
170848b8605Smrg                        int32_t offset2, int32_t stride2)
171848b8605Smrg{
172848b8605Smrg        create_buffer(client, resource, id, 0, fd, width, height, format,
173848b8605Smrg                      offset0, stride0, offset1, stride1, offset2, stride2);
174848b8605Smrg        close(fd);
175848b8605Smrg}
176848b8605Smrg
177848b8605Smrgstatic void
178848b8605Smrgdrm_authenticate(struct wl_client *client,
179848b8605Smrg		 struct wl_resource *resource, uint32_t id)
180848b8605Smrg{
181b8e80941Smrg	struct wl_drm *drm = wl_resource_get_user_data(resource);
182848b8605Smrg
183b8e80941Smrg	if (drm->callbacks.authenticate(drm->user_data, id) < 0)
184848b8605Smrg		wl_resource_post_error(resource,
185848b8605Smrg				       WL_DRM_ERROR_AUTHENTICATE_FAIL,
186848b8605Smrg				       "authenicate failed");
187848b8605Smrg	else
188848b8605Smrg		wl_resource_post_event(resource, WL_DRM_AUTHENTICATED);
189848b8605Smrg}
190848b8605Smrg
191b8e80941Smrgstatic const struct wl_drm_interface drm_interface = {
192848b8605Smrg	drm_authenticate,
193848b8605Smrg	drm_create_buffer,
194848b8605Smrg        drm_create_planar_buffer,
195848b8605Smrg        drm_create_prime_buffer
196848b8605Smrg};
197848b8605Smrg
198848b8605Smrgstatic void
199848b8605Smrgbind_drm(struct wl_client *client, void *data, uint32_t version, uint32_t id)
200848b8605Smrg{
201848b8605Smrg	struct wl_drm *drm = data;
202848b8605Smrg	struct wl_resource *resource;
203848b8605Smrg        uint32_t capabilities;
204848b8605Smrg
205848b8605Smrg	resource = wl_resource_create(client, &wl_drm_interface,
206848b8605Smrg				      MIN(version, 2), id);
207848b8605Smrg	if (!resource) {
208848b8605Smrg		wl_client_post_no_memory(client);
209848b8605Smrg		return;
210848b8605Smrg	}
211848b8605Smrg
212848b8605Smrg	wl_resource_set_implementation(resource, &drm_interface, data, NULL);
213848b8605Smrg
214848b8605Smrg	wl_resource_post_event(resource, WL_DRM_DEVICE, drm->device_name);
215b8e80941Smrg
216b8e80941Smrg	if (drm->callbacks.is_format_supported(drm->user_data,
217b8e80941Smrg					       WL_DRM_FORMAT_ARGB2101010)) {
218b8e80941Smrg		wl_resource_post_event(resource, WL_DRM_FORMAT,
219b8e80941Smrg				       WL_DRM_FORMAT_ARGB2101010);
220b8e80941Smrg	}
221b8e80941Smrg
222b8e80941Smrg	if (drm->callbacks.is_format_supported(drm->user_data,
223b8e80941Smrg					       WL_DRM_FORMAT_XRGB2101010)) {
224b8e80941Smrg		wl_resource_post_event(resource, WL_DRM_FORMAT,
225b8e80941Smrg				       WL_DRM_FORMAT_XRGB2101010);
226b8e80941Smrg	}
227b8e80941Smrg
228b8e80941Smrg	if (drm->callbacks.is_format_supported(drm->user_data,
229b8e80941Smrg					       WL_DRM_FORMAT_ABGR2101010)) {
230b8e80941Smrg		wl_resource_post_event(resource, WL_DRM_FORMAT,
231b8e80941Smrg				       WL_DRM_FORMAT_ABGR2101010);
232b8e80941Smrg	}
233b8e80941Smrg
234b8e80941Smrg	if (drm->callbacks.is_format_supported(drm->user_data,
235b8e80941Smrg					       WL_DRM_FORMAT_XBGR2101010)) {
236b8e80941Smrg		wl_resource_post_event(resource, WL_DRM_FORMAT,
237b8e80941Smrg				       WL_DRM_FORMAT_XBGR2101010);
238b8e80941Smrg	}
239b8e80941Smrg
240848b8605Smrg	wl_resource_post_event(resource, WL_DRM_FORMAT,
241848b8605Smrg			       WL_DRM_FORMAT_ARGB8888);
242848b8605Smrg	wl_resource_post_event(resource, WL_DRM_FORMAT,
243848b8605Smrg			       WL_DRM_FORMAT_XRGB8888);
244848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT,
245848b8605Smrg                               WL_DRM_FORMAT_RGB565);
246848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV410);
247848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV411);
248848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV420);
249848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV422);
250848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUV444);
251848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV12);
252848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_NV16);
253848b8605Smrg        wl_resource_post_event(resource, WL_DRM_FORMAT, WL_DRM_FORMAT_YUYV);
254848b8605Smrg
255848b8605Smrg        capabilities = 0;
256848b8605Smrg        if (drm->flags & WAYLAND_DRM_PRIME)
257848b8605Smrg           capabilities |= WL_DRM_CAPABILITY_PRIME;
258848b8605Smrg
259848b8605Smrg        if (version >= 2)
260848b8605Smrg           wl_resource_post_event(resource, WL_DRM_CAPABILITIES, capabilities);
261848b8605Smrg}
262848b8605Smrg
263848b8605Smrgstruct wl_drm *
264848b8605Smrgwayland_drm_init(struct wl_display *display, char *device_name,
265b8e80941Smrg                 const struct wayland_drm_callbacks *callbacks, void *user_data,
266848b8605Smrg                 uint32_t flags)
267848b8605Smrg{
268848b8605Smrg	struct wl_drm *drm;
269848b8605Smrg
270848b8605Smrg	drm = malloc(sizeof *drm);
271b8e80941Smrg	if (!drm)
272b8e80941Smrg		return NULL;
273848b8605Smrg
274848b8605Smrg	drm->display = display;
275848b8605Smrg	drm->device_name = strdup(device_name);
276b8e80941Smrg	drm->callbacks = *callbacks;
277848b8605Smrg	drm->user_data = user_data;
278848b8605Smrg        drm->flags = flags;
279848b8605Smrg
280848b8605Smrg        drm->buffer_interface.destroy = buffer_destroy;
281848b8605Smrg
282848b8605Smrg	drm->wl_drm_global =
283848b8605Smrg		wl_global_create(display, &wl_drm_interface, 2,
284848b8605Smrg				 drm, bind_drm);
285848b8605Smrg
286848b8605Smrg	return drm;
287848b8605Smrg}
288848b8605Smrg
289848b8605Smrgvoid
290848b8605Smrgwayland_drm_uninit(struct wl_drm *drm)
291848b8605Smrg{
292848b8605Smrg	free(drm->device_name);
293848b8605Smrg
294848b8605Smrg	wl_global_destroy(drm->wl_drm_global);
295848b8605Smrg
296848b8605Smrg	free(drm);
297848b8605Smrg}
298