OSDN Git Service

add (untested) pipe support
[android-x86/external-drm_gralloc.git] / gralloc_drm_pipe.c
1 /*
2  * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3  * Copyright (C) 2010-2011 LunarG Inc.
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 shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 #define LOG_TAG "GRALLOC-PIPE"
25
26 #include <cutils/log.h>
27 #include <errno.h>
28
29 #include <pipe/p_screen.h>
30 #include <pipe/p_context.h>
31 #include <state_tracker/drm_driver.h>
32 #include <util/u_inlines.h>
33 #include <util/u_memory.h>
34
35 #include "gralloc_drm.h"
36 #include "gralloc_drm_priv.h"
37
38 struct pipe_manager {
39         struct gralloc_drm_drv_t base;
40
41         int fd;
42         char name[16];
43         pthread_mutex_t mutex;
44         struct pipe_screen *screen;
45         struct pipe_context *context;
46 };
47
48 struct pipe_buffer {
49         struct gralloc_drm_bo_t base;
50
51         struct pipe_resource *resource;
52         struct winsys_handle winsys;
53
54         struct pipe_transfer *transfer;
55 };
56
57 static enum pipe_format get_pipe_format(int format)
58 {
59         enum pipe_format fmt;
60
61         switch (format) {
62         case HAL_PIXEL_FORMAT_RGBA_8888:
63                 fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
64                 break;
65         case HAL_PIXEL_FORMAT_RGBX_8888:
66                 fmt = PIPE_FORMAT_R8G8B8X8_UNORM;
67                 break;
68         case HAL_PIXEL_FORMAT_RGB_888:
69                 fmt = PIPE_FORMAT_R8G8B8_UNORM;
70                 break;
71         case HAL_PIXEL_FORMAT_RGB_565:
72                 fmt = PIPE_FORMAT_B5G6R5_UNORM;
73                 break;
74         case HAL_PIXEL_FORMAT_BGRA_8888:
75                 fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
76                 break;
77         case HAL_PIXEL_FORMAT_RGBA_5551:
78         case HAL_PIXEL_FORMAT_RGBA_4444:
79         default:
80                 fmt = PIPE_FORMAT_NONE;
81                 break;
82         }
83
84         return fmt;
85 }
86
87 static unsigned get_pipe_bind(int usage)
88 {
89         unsigned bind = PIPE_BIND_SHARED;
90
91         if (usage & GRALLOC_USAGE_SW_READ_MASK)
92                 bind |= PIPE_BIND_TRANSFER_READ;
93         if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
94                 bind |= PIPE_BIND_TRANSFER_WRITE;
95
96         if (usage & GRALLOC_USAGE_HW_TEXTURE)
97                 bind |= PIPE_BIND_SAMPLER_VIEW;
98         if (usage & GRALLOC_USAGE_HW_RENDER)
99                 bind |= PIPE_BIND_RENDER_TARGET;
100         if (usage & GRALLOC_USAGE_HW_FB) {
101                 bind |= PIPE_BIND_RENDER_TARGET;
102                 bind |= PIPE_BIND_SCANOUT;
103         }
104
105         return bind;
106 }
107
108 static struct pipe_buffer *get_pipe_buffer_locked(struct pipe_manager *pm,
109                 const struct gralloc_drm_handle_t *handle)
110 {
111         struct pipe_buffer *buf;
112         struct pipe_resource templ;
113
114         memset(&templ, 0, sizeof(templ));
115         templ.format = get_pipe_format(handle->format);
116         templ.bind = get_pipe_bind(handle->usage);
117         templ.target = PIPE_TEXTURE_2D;
118
119         if (templ.format == PIPE_FORMAT_NONE ||
120             !pm->screen->is_format_supported(pm->screen, templ.format,
121                                 templ.target, 0, templ.bind)) {
122                 LOGE("unsupported format 0x%x", handle->format);
123                 return NULL;
124         }
125
126         buf = CALLOC(1, sizeof(*buf));
127         if (!buf) {
128                 LOGE("failed to allocate pipe buffer");
129                 return NULL;
130         }
131
132         templ.width0 = handle->width;
133         templ.height0 = handle->height;
134         templ.depth0 = 1;
135
136         if (handle->name) {
137                 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
138                 buf->winsys.handle = handle->name;
139                 buf->winsys.stride = handle->stride;
140
141                 buf->resource = pm->screen->resource_from_handle(pm->screen,
142                                 &templ, &buf->winsys);
143                 if (!buf->resource)
144                         goto fail;
145         }
146         else {
147                 buf->resource =
148                         pm->screen->resource_create(pm->screen, &templ);
149                 if (!buf->resource)
150                         goto fail;
151
152                 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
153                 if (!pm->screen->resource_get_handle(pm->screen,
154                                         buf->resource, &buf->winsys))
155                         goto fail;
156         }
157
158         /* need the gem handle for fb */
159         if (handle->usage & GRALLOC_USAGE_HW_FB) {
160                 struct winsys_handle tmp;
161
162                 memset(&tmp, 0, sizeof(tmp));
163                 tmp.type = DRM_API_HANDLE_TYPE_KMS;
164                 if (!pm->screen->resource_get_handle(pm->screen,
165                                         buf->resource, &tmp))
166                         goto fail;
167
168                 buf->base.fb_handle = tmp.handle;
169         }
170
171         return buf;
172
173 fail:
174         LOGE("failed to allocate pipe buffer");
175         if (buf->resource)
176                 pipe_resource_reference(&buf->resource, NULL);
177         FREE(buf);
178
179         return NULL;
180 }
181
182 static struct gralloc_drm_bo_t *pipe_alloc(struct gralloc_drm_drv_t *drv,
183                 struct gralloc_drm_handle_t *handle)
184 {
185         struct pipe_manager *pm = (struct pipe_manager *) drv;
186         struct pipe_buffer *buf;
187
188         pthread_mutex_lock(&pm->mutex);
189         buf = get_pipe_buffer_locked(pm, handle);
190         pthread_mutex_unlock(&pm->mutex);
191
192         if (buf) {
193                 handle->name = (int) buf->winsys.handle;
194                 handle->stride = (int) buf->winsys.stride;
195
196                 buf->base.handle = handle;
197         }
198
199         return &buf->base;
200 }
201
202 static void pipe_free(struct gralloc_drm_drv_t *drv, struct gralloc_drm_bo_t *bo)
203 {
204         struct pipe_manager *pm = (struct pipe_manager *) drv;
205         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
206
207         pthread_mutex_lock(&pm->mutex);
208
209         if (buf->transfer)
210                 pipe_transfer_destroy(pm->context, buf->transfer);
211         pipe_resource_reference(&buf->resource, NULL);
212
213         pthread_mutex_unlock(&pm->mutex);
214
215         FREE(buf);
216 }
217
218 static int pipe_map(struct gralloc_drm_drv_t *drv,
219                 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
220                 int enable_write, void **addr)
221 {
222         struct pipe_manager *pm = (struct pipe_manager *) drv;
223         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
224         int err = 0;
225
226         pthread_mutex_lock(&pm->mutex);
227
228         /* need a context to get transfer */
229         if (!pm->context) {
230                 pm->context = pm->screen->context_create(pm->screen, NULL);
231                 if (!pm->context) {
232                         LOGE("failed to create pipe context");
233                         err = -ENOMEM;
234                 }
235         }
236
237         if (!err) {
238                 enum pipe_transfer_usage usage;
239
240                 usage = PIPE_TRANSFER_READ;
241                 if (enable_write)
242                         usage |= PIPE_TRANSFER_WRITE;
243
244                 assert(!buf->transfer);
245
246                 /*
247                  * ignore x, y, w and h so that returned addr points at the
248                  * start of the buffer
249                  */
250                 buf->transfer = pipe_get_transfer(pm->context, buf->resource,
251                                 0, 0, usage, 0, 0,
252                                 buf->resource->width0, buf->resource->height0);
253                 if (buf->transfer)
254                         *addr = pipe_transfer_map(pm->context, buf->transfer);
255                 else
256                         err = -ENOMEM;
257         }
258
259         pthread_mutex_unlock(&pm->mutex);
260
261         return err;
262 }
263
264 static void pipe_unmap(struct gralloc_drm_drv_t *drv,
265                 struct gralloc_drm_bo_t *bo)
266 {
267         struct pipe_manager *pm = (struct pipe_manager *) drv;
268         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
269
270         pthread_mutex_lock(&pm->mutex);
271
272         assert(buf && buf->transfer);
273
274         pipe_transfer_unmap(pm->context, buf->transfer);
275         pipe_transfer_destroy(pm->context, buf->transfer);
276         buf->transfer = NULL;
277
278         pm->context->flush(pm->context, NULL);
279
280         pthread_mutex_unlock(&pm->mutex);
281 }
282
283 static void pipe_init_kms_features(struct gralloc_drm_drv_t *drv, struct gralloc_drm_t *drm)
284 {
285         struct pipe_manager *pm = (struct pipe_manager *) drv;
286
287         drm->mode_dirty_fb = (strcmp(pm->name, "vmwgfx") == 0);
288         drm->swap_mode = DRM_SWAP_FLIP;
289         drm->mode_sync_flip = 1;
290         drm->swap_interval = 1;
291         drm->vblank_secondary = 0;
292 }
293
294 static void pipe_destroy(struct gralloc_drm_drv_t *drv)
295 {
296         struct pipe_manager *pm = (struct pipe_manager *) drv;
297
298         if (pm->context)
299                 pm->context->destroy(pm->context);
300         pm->screen->destroy(pm->screen);
301         FREE(pm);
302 }
303
304 /* for nouveau */
305 #include "nouveau/drm/nouveau_drm_public.h"
306 /* for debug */
307 #include "target-helpers/inline_debug_helper.h"
308
309 static int pipe_init_screen(struct pipe_manager *pm)
310 {
311         struct pipe_screen *screen;
312         int err = 0;
313
314         if (strcmp(pm->name, "nouveau") == 0) {
315                 screen = nouveau_drm_screen_create(pm->fd);
316                 if (!screen)
317                         err = -EINVAL;
318         }
319         else {
320                 LOGW("unknown driver %s", pm->name);
321                 screen = NULL;
322                 err = -EINVAL;
323         }
324
325         if (screen)
326                 screen = debug_screen_wrap(screen);
327
328         pm->screen = screen;
329
330         return err;
331 }
332
333 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_pipe(int fd, const char *name)
334 {
335         struct pipe_manager *pm;
336
337         pm = CALLOC(1, sizeof(*pm));
338         if (!pm) {
339                 LOGE("failed to allocate pipe manager for %s", name);
340                 return NULL;
341         }
342
343         pm->fd = fd;
344         strncpy(pm->name, name, sizeof(pm->name) - 1);
345
346         pthread_mutex_init(&pm->mutex, NULL);
347
348         if (pipe_init_screen(pm)) {
349                 FREE(pm);
350                 return NULL;
351         }
352
353         pm->base.destroy = pipe_destroy;
354         pm->base.init_kms_features = pipe_init_kms_features;
355         pm->base.alloc = pipe_alloc;
356         pm->base.free = pipe_free;
357         pm->base.map = pipe_map;
358         pm->base.unmap = pipe_unmap;
359
360         return &pm->base;
361 }