OSDN Git Service

Revert "TEMP HACK: make non-standalone surfaceflinger work"
[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 #include <dlfcn.h>
29
30 #include <pipe/p_screen.h>
31 #include <pipe/p_context.h>
32 #include <state_tracker/drm_driver.h>
33 #include <util/u_inlines.h>
34 #include <util/u_memory.h>
35
36 #include "gralloc_drm.h"
37 #include "gralloc_drm_priv.h"
38
39 #if defined(__LP64__)
40 #define DRI_LIBRARY_PATH "/system/lib64/dri"
41 #else
42 #define DRI_LIBRARY_PATH "/system/lib/dri"
43 #endif
44
45 struct pipe_manager {
46         struct gralloc_drm_drv_t base;
47
48         int fd;
49         void *gallium;
50         pthread_mutex_t mutex;
51         struct pipe_loader_device *dev;
52         struct pipe_screen *screen;
53         struct pipe_context *context;
54 };
55
56 struct pipe_buffer {
57         struct gralloc_drm_bo_t base;
58
59         struct pipe_resource *resource;
60         struct winsys_handle winsys;
61
62         struct pipe_transfer *transfer;
63 };
64
65 static enum pipe_format get_pipe_format(int format)
66 {
67         enum pipe_format fmt;
68
69         switch (format) {
70         case HAL_PIXEL_FORMAT_RGBA_8888:
71                 fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
72                 break;
73         case HAL_PIXEL_FORMAT_RGBX_8888:
74                 fmt = PIPE_FORMAT_R8G8B8X8_UNORM;
75                 break;
76         case HAL_PIXEL_FORMAT_RGB_888:
77                 fmt = PIPE_FORMAT_R8G8B8_UNORM;
78                 break;
79         case HAL_PIXEL_FORMAT_RGB_565:
80                 fmt = PIPE_FORMAT_B5G6R5_UNORM;
81                 break;
82         case HAL_PIXEL_FORMAT_BGRA_8888:
83                 fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
84                 break;
85         case HAL_PIXEL_FORMAT_YV12:
86         case HAL_PIXEL_FORMAT_DRM_NV12:
87         case HAL_PIXEL_FORMAT_YCbCr_422_SP:
88         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
89         default:
90                 fmt = PIPE_FORMAT_NONE;
91                 break;
92         }
93
94         return fmt;
95 }
96
97 static unsigned get_pipe_bind(int usage)
98 {
99         unsigned bind = PIPE_BIND_SHARED;
100
101         if (usage & GRALLOC_USAGE_SW_READ_MASK)
102                 bind |= PIPE_BIND_TRANSFER_READ;
103         if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
104                 bind |= PIPE_BIND_TRANSFER_WRITE;
105
106         if (usage & GRALLOC_USAGE_HW_TEXTURE)
107                 bind |= PIPE_BIND_SAMPLER_VIEW;
108         if (usage & GRALLOC_USAGE_HW_RENDER)
109                 bind |= PIPE_BIND_RENDER_TARGET;
110         if (usage & GRALLOC_USAGE_HW_FB) {
111                 bind |= PIPE_BIND_RENDER_TARGET;
112                 bind |= PIPE_BIND_SCANOUT;
113         }
114
115         return bind;
116 }
117
118 static struct pipe_buffer *get_pipe_buffer_locked(struct pipe_manager *pm,
119                 const struct gralloc_drm_handle_t *handle)
120 {
121         struct pipe_buffer *buf;
122         struct pipe_resource templ;
123
124         memset(&templ, 0, sizeof(templ));
125         templ.format = get_pipe_format(handle->format);
126         templ.bind = get_pipe_bind(handle->usage);
127         templ.target = PIPE_TEXTURE_2D;
128
129         if (templ.format == PIPE_FORMAT_NONE ||
130             !pm->screen->is_format_supported(pm->screen, templ.format,
131                                 templ.target, 0, templ.bind)) {
132                 ALOGE("unsupported format 0x%x", handle->format);
133                 return NULL;
134         }
135
136         buf = CALLOC(1, sizeof(*buf));
137         if (!buf) {
138                 ALOGE("failed to allocate pipe buffer");
139                 return NULL;
140         }
141
142         templ.width0 = handle->width;
143         templ.height0 = handle->height;
144         templ.depth0 = 1;
145         templ.array_size = 1;
146
147         if (handle->name) {
148                 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
149                 buf->winsys.handle = handle->name;
150                 buf->winsys.stride = handle->stride;
151
152                 buf->resource = pm->screen->resource_from_handle(pm->screen,
153                                 &templ, &buf->winsys);
154                 if (!buf->resource)
155                         goto fail;
156         }
157         else {
158                 buf->resource =
159                         pm->screen->resource_create(pm->screen, &templ);
160                 if (!buf->resource)
161                         goto fail;
162
163                 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
164                 if (!pm->screen->resource_get_handle(pm->screen,
165                                         buf->resource, &buf->winsys))
166                         goto fail;
167         }
168
169         /* need the gem handle for fb */
170         if (handle->usage & GRALLOC_USAGE_HW_FB) {
171                 struct winsys_handle tmp;
172
173                 memset(&tmp, 0, sizeof(tmp));
174                 tmp.type = DRM_API_HANDLE_TYPE_KMS;
175                 if (!pm->screen->resource_get_handle(pm->screen,
176                                         buf->resource, &tmp))
177                         goto fail;
178
179                 buf->base.fb_handle = tmp.handle;
180         }
181
182         return buf;
183
184 fail:
185         ALOGE("failed to allocate pipe buffer");
186         if (buf->resource)
187                 pipe_resource_reference(&buf->resource, NULL);
188         FREE(buf);
189
190         return NULL;
191 }
192
193 static struct gralloc_drm_bo_t *pipe_alloc(struct gralloc_drm_drv_t *drv,
194                 struct gralloc_drm_handle_t *handle)
195 {
196         struct pipe_manager *pm = (struct pipe_manager *) drv;
197         struct pipe_buffer *buf;
198
199         pthread_mutex_lock(&pm->mutex);
200         buf = get_pipe_buffer_locked(pm, handle);
201         pthread_mutex_unlock(&pm->mutex);
202
203         if (buf) {
204                 handle->name = (int) buf->winsys.handle;
205                 handle->stride = (int) buf->winsys.stride;
206
207                 buf->base.handle = handle;
208         }
209
210         return &buf->base;
211 }
212
213 static void pipe_free(struct gralloc_drm_drv_t *drv, struct gralloc_drm_bo_t *bo)
214 {
215         struct pipe_manager *pm = (struct pipe_manager *) drv;
216         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
217
218         pthread_mutex_lock(&pm->mutex);
219
220         if (buf->transfer)
221                 pipe_transfer_unmap(pm->context, buf->transfer);
222         pipe_resource_reference(&buf->resource, NULL);
223
224         pthread_mutex_unlock(&pm->mutex);
225
226         FREE(buf);
227 }
228
229 static int pipe_map(struct gralloc_drm_drv_t *drv,
230                 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
231                 int enable_write, void **addr)
232 {
233         struct pipe_manager *pm = (struct pipe_manager *) drv;
234         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
235         int err = 0;
236
237         pthread_mutex_lock(&pm->mutex);
238
239         /* need a context to get transfer */
240         if (!pm->context) {
241                 pm->context = pm->screen->context_create(pm->screen, NULL, 0);
242                 if (!pm->context) {
243                         ALOGE("failed to create pipe context");
244                         err = -ENOMEM;
245                 }
246         }
247
248         if (!err) {
249                 enum pipe_transfer_usage usage;
250
251                 usage = PIPE_TRANSFER_READ;
252                 if (enable_write)
253                         usage |= PIPE_TRANSFER_WRITE;
254
255                 assert(!buf->transfer);
256
257                 /*
258                  * ignore x, y, w and h so that returned addr points at the
259                  * start of the buffer
260                  */
261                 *addr = pipe_transfer_map(pm->context, buf->resource,
262                                           0, 0, usage, 0, 0,
263                                           buf->resource->width0, buf->resource->height0,
264                                           &buf->transfer);
265                 if (*addr == NULL)
266                         err = -ENOMEM;
267         }
268
269         pthread_mutex_unlock(&pm->mutex);
270
271         return err;
272 }
273
274 static void pipe_unmap(struct gralloc_drm_drv_t *drv,
275                 struct gralloc_drm_bo_t *bo)
276 {
277         struct pipe_manager *pm = (struct pipe_manager *) drv;
278         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
279
280         pthread_mutex_lock(&pm->mutex);
281
282         assert(buf && buf->transfer);
283
284         pipe_transfer_unmap(pm->context, buf->transfer);
285         buf->transfer = NULL;
286
287         pm->context->flush(pm->context, NULL, 0);
288
289         pthread_mutex_unlock(&pm->mutex);
290 }
291
292 static void pipe_blit(struct gralloc_drm_drv_t *drv,
293                 struct gralloc_drm_bo_t *dst_bo,
294                 struct gralloc_drm_bo_t *src_bo,
295                 uint16_t dst_x1, uint16_t dst_y1,
296                 uint16_t dst_x2, uint16_t dst_y2,
297                 uint16_t src_x1, uint16_t src_y1,
298                 uint16_t src_x2, uint16_t src_y2)
299 {
300         struct pipe_manager *pm = (struct pipe_manager *) drv;
301         struct pipe_buffer *dst = (struct pipe_buffer *) dst_bo;
302         struct pipe_buffer *src = (struct pipe_buffer *) src_bo;
303         struct pipe_box src_box;
304
305         if (dst_bo->handle->width != src_bo->handle->width ||
306             dst_bo->handle->height != src_bo->handle->height ||
307             dst_bo->handle->stride != src_bo->handle->stride ||
308             dst_bo->handle->format != src_bo->handle->format) {
309                 ALOGE("copy between incompatible buffers");
310                 return;
311         }
312
313         if (dst_x2 > dst_bo->handle->width)
314                 dst_x2 = dst_bo->handle->width;
315         if (dst_y2 > dst_bo->handle->height)
316                 dst_y2 = dst_bo->handle->height;
317
318         if (src_x2 <= src_x1 || src_y2 <= src_y1)
319                 return;
320
321         u_box_2d(src_x1, src_y1, src_x2 - src_x1, src_y2 - src_y1, &src_box);
322
323         pthread_mutex_lock(&pm->mutex);
324
325         /* need a context for copying */
326         if (!pm->context) {
327                 pm->context = pm->screen->context_create(pm->screen, NULL, 0);
328                 if (!pm->context) {
329                         ALOGE("failed to create pipe context");
330                         pthread_mutex_unlock(&pm->mutex);
331                         return;
332                 }
333         }
334
335         pm->context->resource_copy_region(pm->context,
336                         dst->resource, 0, dst_x1, dst_y1, 0,
337                         src->resource, 0, &src_box);
338         pm->context->flush(pm->context, NULL, 0);
339
340         pthread_mutex_unlock(&pm->mutex);
341 }
342
343 static void pipe_init_kms_features(struct gralloc_drm_drv_t *drv, struct gralloc_drm_t *drm)
344 {
345         struct pipe_manager *pm = (struct pipe_manager *) drv;
346
347         switch (drm->primary.fb_format) {
348         case HAL_PIXEL_FORMAT_BGRA_8888:
349         case HAL_PIXEL_FORMAT_RGB_565:
350                 break;
351         default:
352                 drm->primary.fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
353                 break;
354         }
355
356         drm->mode_quirk_vmwgfx = 0;
357         drm->swap_mode = DRM_SWAP_FLIP;
358         drm->mode_sync_flip = 1;
359         drm->swap_interval = 1;
360         drm->vblank_secondary = 0;
361 }
362
363 static void pipe_destroy(struct gralloc_drm_drv_t *drv)
364 {
365         struct pipe_manager *pm = (struct pipe_manager *) drv;
366
367         if (pm->context)
368                 pm->context->destroy(pm->context);
369         pm->screen->destroy(pm->screen);
370         dlclose(pm->gallium);
371         FREE(pm);
372 }
373
374 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_pipe(int fd, const char *name)
375 {
376         struct pipe_manager *pm;
377         struct pipe_screen *(*load_pipe_screen)(struct pipe_loader_device **dev, int fd);
378
379         pm = CALLOC(1, sizeof(*pm));
380         if (!pm) {
381                 ALOGE("failed to allocate pipe manager for %s", name);
382                 return NULL;
383         }
384
385         pm->fd = fd;
386         pthread_mutex_init(&pm->mutex, NULL);
387
388         pm->gallium = dlopen(DRI_LIBRARY_PATH"/gallium_dri.so", RTLD_NOW | RTLD_GLOBAL);
389         if (!pm->gallium)
390                 goto err_open;
391
392         load_pipe_screen = dlsym(pm->gallium, "load_pipe_screen");
393         if (!load_pipe_screen)
394                 goto err_load;
395
396         pm->screen = load_pipe_screen(&pm->dev, fd);
397         if (!pm->screen)
398                 goto err_load;
399
400         pm->base.destroy = pipe_destroy;
401         pm->base.init_kms_features = pipe_init_kms_features;
402         pm->base.alloc = pipe_alloc;
403         pm->base.free = pipe_free;
404         pm->base.map = pipe_map;
405         pm->base.unmap = pipe_unmap;
406         pm->base.blit = pipe_blit;
407
408         return &pm->base;
409
410 err_load:
411         dlclose(pm->gallium);
412 err_open:
413         FREE(pm);
414         return NULL;
415 }