OSDN Git Service

gralloc: set supported planes for buffers on allocation
[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 driver[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         case HAL_PIXEL_FORMAT_YV12:
80         case HAL_PIXEL_FORMAT_DRM_NV12:
81         case HAL_PIXEL_FORMAT_YCbCr_422_SP:
82         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
83         default:
84                 fmt = PIPE_FORMAT_NONE;
85                 break;
86         }
87
88         return fmt;
89 }
90
91 static unsigned get_pipe_bind(int usage)
92 {
93         unsigned bind = PIPE_BIND_SHARED;
94
95         if (usage & GRALLOC_USAGE_SW_READ_MASK)
96                 bind |= PIPE_BIND_TRANSFER_READ;
97         if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
98                 bind |= PIPE_BIND_TRANSFER_WRITE;
99
100         if (usage & GRALLOC_USAGE_HW_TEXTURE)
101                 bind |= PIPE_BIND_SAMPLER_VIEW;
102         if (usage & GRALLOC_USAGE_HW_RENDER)
103                 bind |= PIPE_BIND_RENDER_TARGET;
104         if (usage & GRALLOC_USAGE_HW_FB) {
105                 bind |= PIPE_BIND_RENDER_TARGET;
106                 bind |= PIPE_BIND_SCANOUT;
107         }
108
109         return bind;
110 }
111
112 static struct pipe_buffer *get_pipe_buffer_locked(struct pipe_manager *pm,
113                 const struct gralloc_drm_handle_t *handle)
114 {
115         struct pipe_buffer *buf;
116         struct pipe_resource templ;
117
118         memset(&templ, 0, sizeof(templ));
119         templ.format = get_pipe_format(handle->format);
120         templ.bind = get_pipe_bind(handle->usage);
121         templ.target = PIPE_TEXTURE_2D;
122
123         if (templ.format == PIPE_FORMAT_NONE ||
124             !pm->screen->is_format_supported(pm->screen, templ.format,
125                                 templ.target, 0, templ.bind)) {
126                 ALOGE("unsupported format 0x%x", handle->format);
127                 return NULL;
128         }
129
130         buf = CALLOC(1, sizeof(*buf));
131         if (!buf) {
132                 ALOGE("failed to allocate pipe buffer");
133                 return NULL;
134         }
135
136         templ.width0 = handle->width;
137         templ.height0 = handle->height;
138         templ.depth0 = 1;
139         templ.array_size = 1;
140
141         if (handle->name) {
142                 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
143                 buf->winsys.handle = handle->name;
144                 buf->winsys.stride = handle->stride;
145
146                 buf->resource = pm->screen->resource_from_handle(pm->screen,
147                                 &templ, &buf->winsys);
148                 if (!buf->resource)
149                         goto fail;
150         }
151         else {
152                 buf->resource =
153                         pm->screen->resource_create(pm->screen, &templ);
154                 if (!buf->resource)
155                         goto fail;
156
157                 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
158                 if (!pm->screen->resource_get_handle(pm->screen,
159                                         buf->resource, &buf->winsys))
160                         goto fail;
161         }
162
163         /* need the gem handle for fb */
164         if (handle->usage & GRALLOC_USAGE_HW_FB) {
165                 struct winsys_handle tmp;
166
167                 memset(&tmp, 0, sizeof(tmp));
168                 tmp.type = DRM_API_HANDLE_TYPE_KMS;
169                 if (!pm->screen->resource_get_handle(pm->screen,
170                                         buf->resource, &tmp))
171                         goto fail;
172
173                 buf->base.fb_handle = tmp.handle;
174         }
175
176         return buf;
177
178 fail:
179         ALOGE("failed to allocate pipe buffer");
180         if (buf->resource)
181                 pipe_resource_reference(&buf->resource, NULL);
182         FREE(buf);
183
184         return NULL;
185 }
186
187 static struct gralloc_drm_bo_t *pipe_alloc(struct gralloc_drm_drv_t *drv,
188                 struct gralloc_drm_handle_t *handle)
189 {
190         struct pipe_manager *pm = (struct pipe_manager *) drv;
191         struct pipe_buffer *buf;
192
193         pthread_mutex_lock(&pm->mutex);
194         buf = get_pipe_buffer_locked(pm, handle);
195         pthread_mutex_unlock(&pm->mutex);
196
197         if (buf) {
198                 handle->name = (int) buf->winsys.handle;
199                 handle->stride = (int) buf->winsys.stride;
200
201                 buf->base.handle = handle;
202         }
203
204         return &buf->base;
205 }
206
207 static void pipe_free(struct gralloc_drm_drv_t *drv, struct gralloc_drm_bo_t *bo)
208 {
209         struct pipe_manager *pm = (struct pipe_manager *) drv;
210         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
211
212         pthread_mutex_lock(&pm->mutex);
213
214         if (buf->transfer)
215                 pipe_transfer_destroy(pm->context, buf->transfer);
216         pipe_resource_reference(&buf->resource, NULL);
217
218         pthread_mutex_unlock(&pm->mutex);
219
220         FREE(buf);
221 }
222
223 static int pipe_map(struct gralloc_drm_drv_t *drv,
224                 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
225                 int enable_write, void **addr)
226 {
227         struct pipe_manager *pm = (struct pipe_manager *) drv;
228         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
229         int err = 0;
230
231         pthread_mutex_lock(&pm->mutex);
232
233         /* need a context to get transfer */
234         if (!pm->context) {
235                 pm->context = pm->screen->context_create(pm->screen, NULL);
236                 if (!pm->context) {
237                         ALOGE("failed to create pipe context");
238                         err = -ENOMEM;
239                 }
240         }
241
242         if (!err) {
243                 enum pipe_transfer_usage usage;
244
245                 usage = PIPE_TRANSFER_READ;
246                 if (enable_write)
247                         usage |= PIPE_TRANSFER_WRITE;
248
249                 assert(!buf->transfer);
250
251                 /*
252                  * ignore x, y, w and h so that returned addr points at the
253                  * start of the buffer
254                  */
255                 buf->transfer = pipe_get_transfer(pm->context, buf->resource,
256                                 0, 0, usage, 0, 0,
257                                 buf->resource->width0, buf->resource->height0);
258                 if (buf->transfer)
259                         *addr = pipe_transfer_map(pm->context, buf->transfer);
260                 else
261                         err = -ENOMEM;
262         }
263
264         pthread_mutex_unlock(&pm->mutex);
265
266         return err;
267 }
268
269 static void pipe_unmap(struct gralloc_drm_drv_t *drv,
270                 struct gralloc_drm_bo_t *bo)
271 {
272         struct pipe_manager *pm = (struct pipe_manager *) drv;
273         struct pipe_buffer *buf = (struct pipe_buffer *) bo;
274
275         pthread_mutex_lock(&pm->mutex);
276
277         assert(buf && buf->transfer);
278
279         pipe_transfer_unmap(pm->context, buf->transfer);
280         pipe_transfer_destroy(pm->context, buf->transfer);
281         buf->transfer = NULL;
282
283         pm->context->flush(pm->context, NULL);
284
285         pthread_mutex_unlock(&pm->mutex);
286 }
287
288 static void pipe_copy(struct gralloc_drm_drv_t *drv,
289                 struct gralloc_drm_bo_t *dst_bo,
290                 struct gralloc_drm_bo_t *src_bo,
291                 short x1, short y1, short x2, short y2)
292 {
293         struct pipe_manager *pm = (struct pipe_manager *) drv;
294         struct pipe_buffer *dst = (struct pipe_buffer *) dst_bo;
295         struct pipe_buffer *src = (struct pipe_buffer *) src_bo;
296         struct pipe_box src_box;
297
298         if (dst_bo->handle->width != src_bo->handle->width ||
299             dst_bo->handle->height != src_bo->handle->height ||
300             dst_bo->handle->stride != src_bo->handle->stride ||
301             dst_bo->handle->format != src_bo->handle->format) {
302                 ALOGE("copy between incompatible buffers");
303                 return;
304         }
305
306         if (x1 < 0)
307                 x1 = 0;
308         if (y1 < 0)
309                 y1 = 0;
310         if (x2 > dst_bo->handle->width)
311                 x2 = dst_bo->handle->width;
312         if (y2 > dst_bo->handle->height)
313                 y2 = dst_bo->handle->height;
314
315         if (x2 <= x1 || y2 <= y1)
316                 return;
317
318         u_box_2d(x1, y1, x2 - x1, y2 - 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);
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, x1, y1, 0,
334                         src->resource, 0, &src_box);
335         pm->context->flush(pm->context, NULL);
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->fb_format) {
345         case HAL_PIXEL_FORMAT_BGRA_8888:
346         case HAL_PIXEL_FORMAT_RGB_565:
347                 break;
348         default:
349                 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
350                 break;
351         }
352
353         if (strcmp(pm->driver, "vmwgfx") == 0) {
354                 drm->mode_quirk_vmwgfx = 1;
355                 drm->swap_mode = DRM_SWAP_COPY;
356         }
357         else {
358                 drm->mode_quirk_vmwgfx = 0;
359                 drm->swap_mode = DRM_SWAP_FLIP;
360         }
361         drm->mode_sync_flip = 1;
362         drm->swap_interval = 1;
363         drm->vblank_secondary = 0;
364 }
365
366 static void pipe_destroy(struct gralloc_drm_drv_t *drv)
367 {
368         struct pipe_manager *pm = (struct pipe_manager *) drv;
369
370         if (pm->context)
371                 pm->context->destroy(pm->context);
372         pm->screen->destroy(pm->screen);
373         FREE(pm);
374 }
375
376 /* for nouveau */
377 #include "nouveau/drm/nouveau_drm_public.h"
378 /* for r300 */
379 #include "radeon/drm/radeon_drm_public.h"
380 #include "r300/r300_public.h"
381 /* for r600 */
382 #include "r600/drm/r600_drm_public.h"
383 #include "r600/r600_public.h"
384 /* for vmwgfx */
385 #include "svga/drm/svga_drm_public.h"
386 #include "svga/svga_winsys.h"
387 #include "svga/svga_public.h"
388 /* for debug */
389 #include "target-helpers/inline_debug_helper.h"
390
391 static int pipe_init_screen(struct pipe_manager *pm)
392 {
393         struct pipe_screen *screen = NULL;
394
395 #ifdef ENABLE_PIPE_NOUVEAU
396         if (strcmp(pm->driver, "nouveau") == 0)
397                 screen = nouveau_drm_screen_create(pm->fd);
398 #endif
399 #ifdef ENABLE_PIPE_R300
400         if (strcmp(pm->driver, "r300") == 0) {
401                 struct radeon_winsys *sws = radeon_drm_winsys_create(pm->fd);
402
403                 if (sws) {
404                         screen = r300_screen_create(sws);
405                         if (!screen)
406                                 sws->destroy(sws);
407                 }
408         }
409 #endif
410 #ifdef ENABLE_PIPE_R600
411         if (strcmp(pm->driver, "r600") == 0) {
412                 struct radeon *rw = r600_drm_winsys_create(pm->fd);
413
414                 if (rw) {
415                         screen = r600_screen_create(rw);
416                         if (!screen)
417                                 FREE(rw);
418                 }
419         }
420 #endif
421 #ifdef ENABLE_PIPE_VMWGFX
422         if (strcmp(pm->driver, "vmwgfx") == 0) {
423                 struct svga_winsys_screen *sws =
424                         svga_drm_winsys_screen_create(pm->fd);
425
426                 if (sws) {
427                         screen = svga_screen_create(sws);
428                         if (!screen)
429                                 sws->destroy(sws);
430                 }
431         }
432 #endif
433
434         if (!screen) {
435                 ALOGW("failed to create screen for %s", pm->driver);
436                 return -EINVAL;
437         }
438
439         pm->screen = debug_screen_wrap(screen);
440
441         return 0;
442 }
443
444 #include <xf86drm.h>
445 #include <i915_drm.h>
446 #include <radeon_drm.h>
447 static int pipe_get_pci_id(struct pipe_manager *pm,
448                 const char *name, int *vendor, int *device)
449 {
450         int err = -EINVAL;
451
452         if (strcmp(name, "i915") == 0) {
453                 struct drm_i915_getparam gp;
454
455                 *vendor = 0x8086;
456
457                 memset(&gp, 0, sizeof(gp));
458                 gp.param = I915_PARAM_CHIPSET_ID;
459                 gp.value = device;
460                 err = drmCommandWriteRead(pm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
461         }
462         else if (strcmp(name, "radeon") == 0) {
463                 struct drm_radeon_info info;
464
465                 *vendor = 0x1002;
466
467                 memset(&info, 0, sizeof(info));
468                 info.request = RADEON_INFO_DEVICE_ID;
469                 info.value = (long) device;
470                 err = drmCommandWriteRead(pm->fd, DRM_RADEON_INFO, &info, sizeof(info));
471         }
472         else if (strcmp(name, "nouveau") == 0) {
473                 *vendor = 0x10de;
474                 *device = 0;
475                 err = 0;
476         }
477         else if (strcmp(name, "vmwgfx") == 0) {
478                 *vendor = 0x15ad;
479                 /* assume SVGA II */
480                 *device = 0x0405;
481                 err = 0;
482         }
483         else {
484                 err = -EINVAL;
485         }
486
487         return err;
488 }
489
490 #define DRIVER_MAP_GALLIUM_ONLY
491 #include "pci_ids/pci_id_driver_map.h"
492 static int pipe_find_driver(struct pipe_manager *pm, const char *name)
493 {
494         int vendor, device;
495         int err;
496         const char *driver;
497
498         err = pipe_get_pci_id(pm, name, &vendor, &device);
499         if (!err) {
500                 int idx;
501
502                 /* look up in the driver map */
503                 for (idx = 0; driver_map[idx].driver; idx++) {
504                         int i;
505
506                         if (vendor != driver_map[idx].vendor_id)
507                                 continue;
508
509                         if (driver_map[idx].num_chips_ids == -1)
510                                 break;
511
512                         for (i = 0; i < driver_map[idx].num_chips_ids; i++) {
513                                 if (driver_map[idx].chip_ids[i] == device)
514                                         break;
515                         }
516                         if (i < driver_map[idx].num_chips_ids)
517                                 break;
518                 }
519
520                 driver = driver_map[idx].driver;
521                 err = (driver) ? 0 : -ENODEV;
522         }
523         else {
524                 if (strcmp(name, "vmwgfx") == 0) {
525                         driver = "vmwgfx";
526                         err = 0;
527                 }
528         }
529
530         if (!err)
531                 strncpy(pm->driver, driver, sizeof(pm->driver) - 1);
532
533         return err;
534 }
535
536 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_pipe(int fd, const char *name)
537 {
538         struct pipe_manager *pm;
539
540         pm = CALLOC(1, sizeof(*pm));
541         if (!pm) {
542                 ALOGE("failed to allocate pipe manager for %s", name);
543                 return NULL;
544         }
545
546         pm->fd = fd;
547         pthread_mutex_init(&pm->mutex, NULL);
548
549         if (pipe_find_driver(pm, name)) {
550                 FREE(pm);
551                 return NULL;
552         }
553
554         if (pipe_init_screen(pm)) {
555                 FREE(pm);
556                 return NULL;
557         }
558
559         pm->base.destroy = pipe_destroy;
560         pm->base.init_kms_features = pipe_init_kms_features;
561         pm->base.alloc = pipe_alloc;
562         pm->base.free = pipe_free;
563         pm->base.map = pipe_map;
564         pm->base.unmap = pipe_unmap;
565         pm->base.copy = pipe_copy;
566
567         return &pm->base;
568 }