0c3b1296588c631dad7e66b5f60ec89958fe6d36
[profile/ivi/weston.git] / compositor / drm.c
1 /*
2  * Copyright © 2010 Kristian Høgsberg
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "compositor.h"
24
25 static void
26 drm_authenticate(struct wl_client *client,
27                  struct wl_drm *drm_base, uint32_t id)
28 {
29         struct wlsc_drm *drm = (struct wlsc_drm *) drm_base;
30         struct wlsc_compositor *compositor =
31                 container_of(drm, struct wlsc_compositor, drm);
32
33         if (compositor->authenticate(compositor, id) < 0)
34                 wl_client_post_event(client,
35                                      (struct wl_object *) compositor->wl_display,
36                                      WL_DISPLAY_INVALID_OBJECT, 0);
37         else
38                 wl_client_post_event(client, &drm->object,
39                                      WL_DRM_AUTHENTICATED);
40 }
41
42 static void
43 destroy_buffer(struct wl_resource *resource, struct wl_client *client)
44 {
45         struct wlsc_drm_buffer *buffer =
46                 container_of(resource, struct wlsc_drm_buffer, buffer.resource);
47         struct wlsc_compositor *compositor =
48                 (struct wlsc_compositor *) buffer->buffer.compositor;
49
50         eglDestroyImageKHR(compositor->display, buffer->image);
51         free(buffer);
52 }
53
54 static void
55 buffer_destroy(struct wl_client *client, struct wl_buffer *buffer)
56 {
57         wl_resource_destroy(&buffer->resource, client);
58 }
59
60 const static struct wl_buffer_interface buffer_interface = {
61         buffer_destroy
62 };
63
64 static void
65 drm_buffer_attach(struct wl_buffer *buffer_base, struct wl_surface *surface)
66 {
67         struct wlsc_surface *es = (struct wlsc_surface *) surface;
68         struct wlsc_drm_buffer *buffer =
69                 (struct wlsc_drm_buffer *) buffer_base;
70
71         glBindTexture(GL_TEXTURE_2D, es->texture);
72         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image);
73         es->visual = buffer->buffer.visual;
74 }
75
76 static void
77 drm_buffer_damage(struct wl_buffer *buffer,
78                   struct wl_surface *surface,
79                   int32_t x, int32_t y, int32_t width, int32_t height)
80 {
81 }
82
83 static struct wlsc_drm_buffer *
84 wlsc_drm_buffer_create_for_image(struct wlsc_compositor *compositor,
85                                  EGLImageKHR *image,
86                                  int32_t width, int32_t height,
87                                  struct wl_visual *visual)
88 {
89         struct wlsc_drm_buffer *buffer;
90
91         buffer = malloc(sizeof *buffer);
92         if (buffer == NULL)
93                 return NULL;
94
95         buffer->buffer.compositor = &compositor->compositor;
96         buffer->buffer.width = width;
97         buffer->buffer.height = height;
98         buffer->buffer.visual = visual;
99         buffer->buffer.attach = drm_buffer_attach;
100         buffer->buffer.damage = drm_buffer_damage;
101         buffer->image = image;
102
103         return buffer;
104 }
105
106 static void
107 drm_create_buffer(struct wl_client *client, struct wl_drm *drm_base,
108                   uint32_t id, uint32_t name, int32_t width, int32_t height,
109                   uint32_t stride, struct wl_visual *visual)
110 {
111         struct wlsc_drm *drm = (struct wlsc_drm *) drm_base;
112         struct wlsc_compositor *compositor =
113                 container_of(drm, struct wlsc_compositor, drm);
114         struct wlsc_drm_buffer *buffer;
115         EGLImageKHR image;
116         EGLint attribs[] = {
117                 EGL_WIDTH,              0,
118                 EGL_HEIGHT,             0,
119                 EGL_DRM_BUFFER_STRIDE_MESA,     0,
120                 EGL_DRM_BUFFER_FORMAT_MESA,     EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
121                 EGL_NONE
122         };
123
124         if (visual->object.interface != &wl_visual_interface) {
125                 /* FIXME: Define a real exception event instead of
126                  * abusing this one */
127                 wl_client_post_event(client,
128                                      (struct wl_object *) compositor->wl_display,
129                                      WL_DISPLAY_INVALID_OBJECT, 0);
130                 fprintf(stderr, "invalid visual in create_buffer\n");
131                 return;
132         }
133
134         attribs[1] = width;
135         attribs[3] = height;
136         attribs[5] = stride / 4;
137         image = eglCreateImageKHR(compositor->display,
138                                   EGL_NO_CONTEXT,
139                                   EGL_DRM_BUFFER_MESA,
140                                   (EGLClientBuffer) name, attribs);
141         if (image == NULL) {
142                 /* FIXME: Define a real exception event instead of
143                  * abusing this one */
144                 wl_client_post_event(client,
145                                      (struct wl_object *) compositor->wl_display,
146                                      WL_DISPLAY_INVALID_OBJECT, 0);
147                 fprintf(stderr, "failed to create image for name %d\n", name);
148                 return;
149         }
150
151         buffer = wlsc_drm_buffer_create_for_image(compositor, image,
152                                                   width, height, visual);
153         if (buffer == NULL) {
154                 eglDestroyImageKHR(compositor->display, image);
155                 wl_client_post_no_memory(client);
156                 return;
157         }
158
159         buffer->buffer.resource.object.id = id;
160         buffer->buffer.resource.object.interface = &wl_buffer_interface;
161         buffer->buffer.resource.object.implementation = (void (**)(void))
162                 &buffer_interface;
163
164         buffer->buffer.resource.destroy = destroy_buffer;
165
166         wl_client_add_resource(client, &buffer->buffer.resource);
167 }
168
169 const static struct wl_drm_interface drm_interface = {
170         drm_authenticate,
171         drm_create_buffer
172 };
173
174 static void
175 post_drm_device(struct wl_client *client, struct wl_object *global)
176 {
177         struct wlsc_drm *drm = container_of(global, struct wlsc_drm, object);
178
179         wl_client_post_event(client, global, WL_DRM_DEVICE, drm->filename);
180 }
181
182 int
183 wlsc_drm_init(struct wlsc_compositor *ec, int fd, const char *filename)
184 {
185         struct wlsc_drm *drm = &ec->drm;
186
187         drm->fd = fd;
188         drm->filename = strdup(filename);
189         if (drm->filename == NULL)
190                 return -1;
191
192         drm->object.interface = &wl_drm_interface;
193         drm->object.implementation = (void (**)(void)) &drm_interface;
194         wl_display_add_object(ec->wl_display, &drm->object);
195         wl_display_add_global(ec->wl_display, &drm->object, post_drm_device);
196
197         return 0;
198 }
199
200 struct wlsc_drm_buffer *
201 wlsc_drm_buffer_create(struct wlsc_compositor *ec,
202                        int width, int height, struct wl_visual *visual)
203 {
204         struct wlsc_drm_buffer *buffer;
205         EGLImageKHR image;
206
207         EGLint image_attribs[] = {
208                 EGL_WIDTH,              0,
209                 EGL_HEIGHT,             0,
210                 EGL_DRM_BUFFER_FORMAT_MESA,     EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
211                 EGL_DRM_BUFFER_USE_MESA,        EGL_DRM_BUFFER_USE_SCANOUT_MESA,
212                 EGL_NONE
213         };
214
215         image_attribs[1] = width;
216         image_attribs[3] = height;
217
218         image = eglCreateDRMImageMESA(ec->display, image_attribs);
219         if (image == NULL)
220                 return NULL;
221
222         buffer = wlsc_drm_buffer_create_for_image(ec, image,
223                                                   width, height, visual);
224
225         return buffer;
226 }