OSDN Git Service

gralloc_pipe_drm: add storage_sample_count parameter into is_format_supported
[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/winsys_handle.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 "/vendor/lib64/dri"
41 #else
42 #define DRI_LIBRARY_PATH "/vendor/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_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN))
102                 bind |= PIPE_BIND_LINEAR;
103         if (usage & GRALLOC_USAGE_HW_TEXTURE)
104                 bind |= PIPE_BIND_SAMPLER_VIEW;
105         if (usage & GRALLOC_USAGE_HW_RENDER)
106                 bind |= PIPE_BIND_RENDER_TARGET;
107         if (usage & GRALLOC_USAGE_HW_FB) {
108                 bind |= PIPE_BIND_RENDER_TARGET;
109                 bind |= PIPE_BIND_SCANOUT;
110         }
111
112         return bind;
113 }
114
115 static struct pipe_buffer *get_pipe_buffer_locked(struct pipe_manager *pm,
116                 const struct gralloc_drm_handle_t *handle)
117 {
118         struct pipe_buffer *buf;
119         struct pipe_resource templ;
120
121         memset(&templ, 0, sizeof(templ));
122         templ.format = get_pipe_format(handle->format);
123         templ.bind = get_pipe_bind(handle->usage);
124         templ.target = PIPE_TEXTURE_2D;
125
126         if (templ.format == PIPE_FORMAT_NONE ||
127             !pm->screen->is_format_supported(pm->screen, templ.format,
128                                 templ.target, 0, 0, templ.bind)) {
129                 ALOGE("unsupported format 0x%x", handle->format);
130                 return NULL;
131         }
132
133         buf = CALLOC(1, sizeof(*buf));
134         if (!buf) {
135                 ALOGE("failed to allocate pipe buffer");
136                 return NULL;
137         }
138
139         templ.width0 = handle->width;
140         templ.height0 = handle->height;
141         templ.depth0 = 1;
142         templ.array_size = 1;
143
144         if (handle->name) {
145                 buf->winsys.type = WINSYS_HANDLE_TYPE_SHARED;
146                 buf->winsys.handle = handle->name;
147                 buf->winsys.stride = handle->stride;
148
149                 buf->resource = pm->screen->resource_from_handle(pm->screen,
150                                 &templ, &buf->winsys, PIPE_HANDLE_USAGE_READ_WRITE);
151                 if (!buf->resource)
152                         goto fail;
153         }
154         else {
155                 buf->resource =
156                         pm->screen->resource_create(pm->screen, &templ);
157                 if (!buf->resource)
158                         goto fail;
159
160                 buf->winsys.type = WINSYS_HANDLE_TYPE_SHARED;
161                 if (!pm->screen->resource_get_handle(pm->screen, pm->context,
162                                 buf->resource, &buf->winsys, PIPE_HANDLE_USAGE_READ_WRITE))
163                         goto fail;
164         }
165
166         /* need the gem handle for fb */
167         if (handle->usage & GRALLOC_USAGE_HW_FB) {
168                 struct winsys_handle tmp;
169
170                 memset(&tmp, 0, sizeof(tmp));
171                 tmp.type = WINSYS_HANDLE_TYPE_KMS;
172                 if (!pm->screen->resource_get_handle(pm->screen, pm->context,
173                                 buf->resource, &tmp, PIPE_HANDLE_USAGE_READ_WRITE))
174                         goto fail;
175
176                 buf->base.fb_handle = tmp.handle;
177         }
178
179         return buf;
180
181 fail:
182         ALOGE("failed to allocate pipe buffer");
183         if (buf->resource)
184                 pipe_resource_reference(&buf->resource, NULL);
185         FREE(buf);
186
187         return NULL;
188 }
189
190 static struct gralloc_drm_bo_t *pipe_alloc(struct gralloc_drm_drv_t *drv,
191                 struct gralloc_drm_handle_t *handle)
192 {
193         struct pipe_manager *pm = (struct pipe_manager *) drv;
194         struct pipe_buffer *buf;
195
196         pthread_mutex_lock(&pm->mutex);
197         buf = get_pipe_buffer_locked(pm, handle);
198         pthread_mutex_unlock(&pm->mutex);
199
200         if (buf) {
201                 handle->name = (int) buf->winsys.handle;
202                 handle->stride = (int) buf->winsys.stride;
203
204                 buf->base.handle = handle;
205         }
206
207         return &buf->base;
208 }
209
210 static void pipe_free(struct gralloc_drm_drv_t *drv, struct gralloc_drm_bo_t *bo)
211 {
212         struct pipe_manager *pm = (struct pipe_manager *) drv;
213         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
214
215         pthread_mutex_lock(&pm->mutex);
216
217         if (buf->transfer)
218                 pipe_transfer_unmap(pm->context, buf->transfer);
219         pipe_resource_reference(&buf->resource, NULL);
220
221         pthread_mutex_unlock(&pm->mutex);
222
223         FREE(buf);
224 }
225
226 static int pipe_map(struct gralloc_drm_drv_t *drv,
227                 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
228                 int enable_write, void **addr)
229 {
230         struct pipe_manager *pm = (struct pipe_manager *) drv;
231         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
232         int err = 0;
233
234         pthread_mutex_lock(&pm->mutex);
235
236         /* need a context to get transfer */
237         if (!pm->context) {
238                 pm->context = pm->screen->context_create(pm->screen, NULL, 0);
239                 if (!pm->context) {
240                         ALOGE("failed to create pipe context");
241                         err = -ENOMEM;
242                 }
243         }
244
245         if (!err) {
246                 enum pipe_transfer_usage usage;
247
248                 usage = PIPE_TRANSFER_READ;
249                 if (enable_write)
250                         usage |= PIPE_TRANSFER_WRITE;
251
252                 assert(!buf->transfer);
253
254                 /*
255                  * ignore x, y, w and h so that returned addr points at the
256                  * start of the buffer
257                  */
258                 *addr = pipe_transfer_map(pm->context, buf->resource,
259                                           0, 0, usage, 0, 0,
260                                           buf->resource->width0, buf->resource->height0,
261                                           &buf->transfer);
262                 if (*addr == NULL)
263                         err = -ENOMEM;
264         }
265
266         pthread_mutex_unlock(&pm->mutex);
267
268         return err;
269 }
270
271 static void pipe_unmap(struct gralloc_drm_drv_t *drv,
272                 struct gralloc_drm_bo_t *bo)
273 {
274         struct pipe_manager *pm = (struct pipe_manager *) drv;
275         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
276
277         pthread_mutex_lock(&pm->mutex);
278
279         assert(buf && buf->transfer);
280
281         pipe_transfer_unmap(pm->context, buf->transfer);
282         buf->transfer = NULL;
283
284         pm->context->flush(pm->context, NULL, 0);
285
286         pthread_mutex_unlock(&pm->mutex);
287 }
288
289 static void pipe_blit(struct gralloc_drm_drv_t *drv,
290                 struct gralloc_drm_bo_t *dst_bo,
291                 struct gralloc_drm_bo_t *src_bo,
292                 uint16_t dst_x1, uint16_t dst_y1,
293                 uint16_t dst_x2, uint16_t dst_y2,
294                 uint16_t src_x1, uint16_t src_y1,
295                 uint16_t src_x2, uint16_t src_y2)
296 {
297         struct pipe_manager *pm = (struct pipe_manager *) drv;
298         struct pipe_buffer *dst = (struct pipe_buffer *) dst_bo;
299         struct pipe_buffer *src = (struct pipe_buffer *) src_bo;
300         struct pipe_box src_box;
301
302         if (dst_bo->handle->width != src_bo->handle->width ||
303             dst_bo->handle->height != src_bo->handle->height ||
304             dst_bo->handle->stride != src_bo->handle->stride ||
305             dst_bo->handle->format != src_bo->handle->format) {
306                 ALOGE("copy between incompatible buffers");
307                 return;
308         }
309
310         if (dst_x2 > dst_bo->handle->width)
311                 dst_x2 = dst_bo->handle->width;
312         if (dst_y2 > dst_bo->handle->height)
313                 dst_y2 = dst_bo->handle->height;
314
315         if (src_x2 <= src_x1 || src_y2 <= src_y1)
316                 return;
317
318         u_box_2d(src_x1, src_y1, src_x2 - src_x1, src_y2 - src_y1, &src_box);
319
320         pthread_mutex_lock(&pm->mutex);
321
322         /* need a context for copying */
323         if (!pm->context) {
324                 pm->context = pm->screen->context_create(pm->screen, NULL, 0);
325                 if (!pm->context) {
326                         ALOGE("failed to create pipe context");
327                         pthread_mutex_unlock(&pm->mutex);
328                         return;
329                 }
330         }
331
332         pm->context->resource_copy_region(pm->context,
333                         dst->resource, 0, dst_x1, dst_y1, 0,
334                         src->resource, 0, &src_box);
335         pm->context->flush(pm->context, NULL, 0);
336
337         pthread_mutex_unlock(&pm->mutex);
338 }
339
340 static void pipe_init_kms_features(struct gralloc_drm_drv_t *drv, struct gralloc_drm_t *drm)
341 {
342         struct pipe_manager *pm = (struct pipe_manager *) drv;
343
344         switch (drm->primary->fb_format) {
345         case HAL_PIXEL_FORMAT_BGRA_8888:
346         case HAL_PIXEL_FORMAT_RGB_565:
347                 break;
348         default:
349                 drm->primary->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
350                 break;
351         }
352
353         drm->mode_quirk_vmwgfx = 0;
354         drm->swap_mode = DRM_SWAP_FLIP;
355         drm->mode_sync_flip = 1;
356         drm->swap_interval = 1;
357         drm->vblank_secondary = 0;
358 }
359
360 static void pipe_destroy(struct gralloc_drm_drv_t *drv)
361 {
362         struct pipe_manager *pm = (struct pipe_manager *) drv;
363
364         if (pm->context)
365                 pm->context->destroy(pm->context);
366         pm->screen->destroy(pm->screen);
367         dlclose(pm->gallium);
368         FREE(pm);
369 }
370
371 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_pipe(int fd, const char *name)
372 {
373         struct pipe_manager *pm;
374         struct pipe_screen *(*load_pipe_screen)(struct pipe_loader_device **dev, int fd);
375
376         pm = CALLOC(1, sizeof(*pm));
377         if (!pm) {
378                 ALOGE("failed to allocate pipe manager for %s", name);
379                 return NULL;
380         }
381
382         pm->fd = fd;
383         pthread_mutex_init(&pm->mutex, NULL);
384
385         pm->gallium = dlopen(DRI_LIBRARY_PATH"/gallium_dri.so", RTLD_NOW | RTLD_GLOBAL);
386         if (!pm->gallium)
387                 goto err_open;
388
389         load_pipe_screen = dlsym(pm->gallium, "load_pipe_screen");
390         if (!load_pipe_screen)
391                 goto err_load;
392
393         pm->screen = load_pipe_screen(&pm->dev, fd);
394         if (!pm->screen)
395                 goto err_load;
396
397         pm->base.destroy = pipe_destroy;
398         pm->base.init_kms_features = pipe_init_kms_features;
399         pm->base.alloc = pipe_alloc;
400         pm->base.free = pipe_free;
401         pm->base.map = pipe_map;
402         pm->base.unmap = pipe_unmap;
403         pm->base.blit = pipe_blit;
404
405         return &pm->base;
406
407 err_load:
408         dlclose(pm->gallium);
409 err_open:
410         FREE(pm);
411         return NULL;
412 }