blob: d237b7de92a212d67c8fdb8212f173477805c8c0 [file] [log] [blame]
Chia-I Wua020bfa2011-06-13 08:48:44 +08001/*
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
38struct pipe_manager {
39 struct gralloc_drm_drv_t base;
40
41 int fd;
Chia-I Wu3dcc0152011-07-10 20:17:41 +080042 char driver[16];
Chia-I Wua020bfa2011-06-13 08:48:44 +080043 pthread_mutex_t mutex;
44 struct pipe_screen *screen;
45 struct pipe_context *context;
46};
47
48struct 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
57static 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;
Chia-I Wub65a3f82011-10-27 18:01:23 +080077 case HAL_PIXEL_FORMAT_YV12:
Tapani Pälli45a94512012-12-14 10:43:39 +020078 case HAL_PIXEL_FORMAT_DRM_NV12:
Chia-I Wub65a3f82011-10-27 18:01:23 +080079 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
80 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
Chia-I Wua020bfa2011-06-13 08:48:44 +080081 default:
82 fmt = PIPE_FORMAT_NONE;
83 break;
84 }
85
86 return fmt;
87}
88
89static unsigned get_pipe_bind(int usage)
90{
91 unsigned bind = PIPE_BIND_SHARED;
92
93 if (usage & GRALLOC_USAGE_SW_READ_MASK)
94 bind |= PIPE_BIND_TRANSFER_READ;
95 if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
96 bind |= PIPE_BIND_TRANSFER_WRITE;
97
98 if (usage & GRALLOC_USAGE_HW_TEXTURE)
99 bind |= PIPE_BIND_SAMPLER_VIEW;
100 if (usage & GRALLOC_USAGE_HW_RENDER)
101 bind |= PIPE_BIND_RENDER_TARGET;
102 if (usage & GRALLOC_USAGE_HW_FB) {
103 bind |= PIPE_BIND_RENDER_TARGET;
104 bind |= PIPE_BIND_SCANOUT;
105 }
106
107 return bind;
108}
109
110static struct pipe_buffer *get_pipe_buffer_locked(struct pipe_manager *pm,
111 const struct gralloc_drm_handle_t *handle)
112{
113 struct pipe_buffer *buf;
114 struct pipe_resource templ;
115
116 memset(&templ, 0, sizeof(templ));
117 templ.format = get_pipe_format(handle->format);
118 templ.bind = get_pipe_bind(handle->usage);
119 templ.target = PIPE_TEXTURE_2D;
120
121 if (templ.format == PIPE_FORMAT_NONE ||
122 !pm->screen->is_format_supported(pm->screen, templ.format,
123 templ.target, 0, templ.bind)) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700124 ALOGE("unsupported format 0x%x", handle->format);
Chia-I Wua020bfa2011-06-13 08:48:44 +0800125 return NULL;
126 }
127
128 buf = CALLOC(1, sizeof(*buf));
129 if (!buf) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700130 ALOGE("failed to allocate pipe buffer");
Chia-I Wua020bfa2011-06-13 08:48:44 +0800131 return NULL;
132 }
133
134 templ.width0 = handle->width;
135 templ.height0 = handle->height;
136 templ.depth0 = 1;
Chia-I Wu59eb3d82011-06-13 14:34:21 +0800137 templ.array_size = 1;
Chia-I Wua020bfa2011-06-13 08:48:44 +0800138
139 if (handle->name) {
140 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
141 buf->winsys.handle = handle->name;
142 buf->winsys.stride = handle->stride;
143
144 buf->resource = pm->screen->resource_from_handle(pm->screen,
145 &templ, &buf->winsys);
146 if (!buf->resource)
147 goto fail;
148 }
149 else {
150 buf->resource =
151 pm->screen->resource_create(pm->screen, &templ);
152 if (!buf->resource)
153 goto fail;
154
155 buf->winsys.type = DRM_API_HANDLE_TYPE_SHARED;
156 if (!pm->screen->resource_get_handle(pm->screen,
157 buf->resource, &buf->winsys))
158 goto fail;
159 }
160
161 /* need the gem handle for fb */
162 if (handle->usage & GRALLOC_USAGE_HW_FB) {
163 struct winsys_handle tmp;
164
165 memset(&tmp, 0, sizeof(tmp));
166 tmp.type = DRM_API_HANDLE_TYPE_KMS;
167 if (!pm->screen->resource_get_handle(pm->screen,
168 buf->resource, &tmp))
169 goto fail;
170
171 buf->base.fb_handle = tmp.handle;
172 }
173
174 return buf;
175
176fail:
Charles Johnsonb56dc922012-07-10 17:51:32 -0700177 ALOGE("failed to allocate pipe buffer");
Chia-I Wua020bfa2011-06-13 08:48:44 +0800178 if (buf->resource)
179 pipe_resource_reference(&buf->resource, NULL);
180 FREE(buf);
181
182 return NULL;
183}
184
185static struct gralloc_drm_bo_t *pipe_alloc(struct gralloc_drm_drv_t *drv,
186 struct gralloc_drm_handle_t *handle)
187{
188 struct pipe_manager *pm = (struct pipe_manager *) drv;
189 struct pipe_buffer *buf;
190
191 pthread_mutex_lock(&pm->mutex);
192 buf = get_pipe_buffer_locked(pm, handle);
193 pthread_mutex_unlock(&pm->mutex);
194
195 if (buf) {
196 handle->name = (int) buf->winsys.handle;
197 handle->stride = (int) buf->winsys.stride;
198
199 buf->base.handle = handle;
200 }
201
202 return &buf->base;
203}
204
205static void pipe_free(struct gralloc_drm_drv_t *drv, struct gralloc_drm_bo_t *bo)
206{
207 struct pipe_manager *pm = (struct pipe_manager *) drv;
208 struct pipe_buffer *buf = (struct pipe_buffer *) bo;
209
210 pthread_mutex_lock(&pm->mutex);
211
212 if (buf->transfer)
Chih-Wei Huang4b3db542013-04-11 10:41:50 +0300213 pipe_transfer_unmap(pm->context, buf->transfer);
Chia-I Wua020bfa2011-06-13 08:48:44 +0800214 pipe_resource_reference(&buf->resource, NULL);
215
216 pthread_mutex_unlock(&pm->mutex);
217
218 FREE(buf);
219}
220
221static int pipe_map(struct gralloc_drm_drv_t *drv,
222 struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
223 int enable_write, void **addr)
224{
225 struct pipe_manager *pm = (struct pipe_manager *) drv;
226 struct pipe_buffer *buf = (struct pipe_buffer *) bo;
227 int err = 0;
228
229 pthread_mutex_lock(&pm->mutex);
230
231 /* need a context to get transfer */
232 if (!pm->context) {
233 pm->context = pm->screen->context_create(pm->screen, NULL);
234 if (!pm->context) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700235 ALOGE("failed to create pipe context");
Chia-I Wua020bfa2011-06-13 08:48:44 +0800236 err = -ENOMEM;
237 }
238 }
239
240 if (!err) {
241 enum pipe_transfer_usage usage;
242
243 usage = PIPE_TRANSFER_READ;
244 if (enable_write)
245 usage |= PIPE_TRANSFER_WRITE;
246
247 assert(!buf->transfer);
248
249 /*
250 * ignore x, y, w and h so that returned addr points at the
251 * start of the buffer
252 */
Chih-Wei Huang4b3db542013-04-11 10:41:50 +0300253 *addr = pipe_transfer_map(pm->context, buf->resource,
254 0, 0, usage, 0, 0,
255 buf->resource->width0, buf->resource->height0,
256 &buf->transfer);
257 if (*addr == NULL)
Chia-I Wua020bfa2011-06-13 08:48:44 +0800258 err = -ENOMEM;
259 }
260
261 pthread_mutex_unlock(&pm->mutex);
262
263 return err;
264}
265
266static void pipe_unmap(struct gralloc_drm_drv_t *drv,
267 struct gralloc_drm_bo_t *bo)
268{
269 struct pipe_manager *pm = (struct pipe_manager *) drv;
270 struct pipe_buffer *buf = (struct pipe_buffer *) bo;
271
272 pthread_mutex_lock(&pm->mutex);
273
274 assert(buf && buf->transfer);
275
276 pipe_transfer_unmap(pm->context, buf->transfer);
Chia-I Wua020bfa2011-06-13 08:48:44 +0800277 buf->transfer = NULL;
278
Chih-Wei Huang4b3db542013-04-11 10:41:50 +0300279 pm->context->flush(pm->context, NULL, 0);
Chia-I Wua020bfa2011-06-13 08:48:44 +0800280
281 pthread_mutex_unlock(&pm->mutex);
282}
283
Chia-I Wua020bfa2011-06-13 08:48:44 +0800284static void pipe_destroy(struct gralloc_drm_drv_t *drv)
285{
286 struct pipe_manager *pm = (struct pipe_manager *) drv;
287
288 if (pm->context)
289 pm->context->destroy(pm->context);
290 pm->screen->destroy(pm->screen);
291 FREE(pm);
292}
293
294/* for nouveau */
295#include "nouveau/drm/nouveau_drm_public.h"
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800296/* for r300 */
297#include "radeon/drm/radeon_drm_public.h"
298#include "r300/r300_public.h"
299/* for r600 */
Chih-Wei Huang4b3db542013-04-11 10:41:50 +0300300#include "radeon/drm/radeon_winsys.h"
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800301#include "r600/r600_public.h"
302/* for vmwgfx */
303#include "svga/drm/svga_drm_public.h"
Chia-I Wudb29afe2011-08-24 14:07:06 +0800304#include "svga/svga_winsys.h"
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800305#include "svga/svga_public.h"
Chia-I Wua020bfa2011-06-13 08:48:44 +0800306/* for debug */
307#include "target-helpers/inline_debug_helper.h"
308
309static int pipe_init_screen(struct pipe_manager *pm)
310{
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800311 struct pipe_screen *screen = NULL;
Chia-I Wua020bfa2011-06-13 08:48:44 +0800312
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800313#ifdef ENABLE_PIPE_NOUVEAU
314 if (strcmp(pm->driver, "nouveau") == 0)
Chia-I Wua020bfa2011-06-13 08:48:44 +0800315 screen = nouveau_drm_screen_create(pm->fd);
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800316#endif
317#ifdef ENABLE_PIPE_R300
318 if (strcmp(pm->driver, "r300") == 0) {
319 struct radeon_winsys *sws = radeon_drm_winsys_create(pm->fd);
320
321 if (sws) {
322 screen = r300_screen_create(sws);
323 if (!screen)
324 sws->destroy(sws);
325 }
326 }
327#endif
328#ifdef ENABLE_PIPE_R600
329 if (strcmp(pm->driver, "r600") == 0) {
Chih-Wei Huang4b3db542013-04-11 10:41:50 +0300330 struct radeon_winsys *sws = radeon_drm_winsys_create(pm->fd);
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800331
Chih-Wei Huang4b3db542013-04-11 10:41:50 +0300332 if (sws) {
333 screen = r600_screen_create(sws);
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800334 if (!screen)
Chih-Wei Huang4b3db542013-04-11 10:41:50 +0300335 sws->destroy(sws);
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800336 }
337 }
338#endif
339#ifdef ENABLE_PIPE_VMWGFX
340 if (strcmp(pm->driver, "vmwgfx") == 0) {
341 struct svga_winsys_screen *sws =
342 svga_drm_winsys_screen_create(pm->fd);
343
344 if (sws) {
345 screen = svga_screen_create(sws);
346 if (!screen)
347 sws->destroy(sws);
348 }
349 }
350#endif
351
352 if (!screen) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700353 ALOGW("failed to create screen for %s", pm->driver);
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800354 return -EINVAL;
355 }
356
357 pm->screen = debug_screen_wrap(screen);
358
359 return 0;
360}
361
362#include <xf86drm.h>
363#include <i915_drm.h>
364#include <radeon_drm.h>
365static int pipe_get_pci_id(struct pipe_manager *pm,
366 const char *name, int *vendor, int *device)
367{
368 int err = -EINVAL;
369
370 if (strcmp(name, "i915") == 0) {
371 struct drm_i915_getparam gp;
372
373 *vendor = 0x8086;
374
375 memset(&gp, 0, sizeof(gp));
376 gp.param = I915_PARAM_CHIPSET_ID;
377 gp.value = device;
378 err = drmCommandWriteRead(pm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
379 }
380 else if (strcmp(name, "radeon") == 0) {
381 struct drm_radeon_info info;
382
383 *vendor = 0x1002;
384
385 memset(&info, 0, sizeof(info));
386 info.request = RADEON_INFO_DEVICE_ID;
387 info.value = (long) device;
388 err = drmCommandWriteRead(pm->fd, DRM_RADEON_INFO, &info, sizeof(info));
389 }
390 else if (strcmp(name, "nouveau") == 0) {
391 *vendor = 0x10de;
392 *device = 0;
393 err = 0;
Chia-I Wua020bfa2011-06-13 08:48:44 +0800394 }
Chia-I Wudb29afe2011-08-24 14:07:06 +0800395 else if (strcmp(name, "vmwgfx") == 0) {
396 *vendor = 0x15ad;
397 /* assume SVGA II */
398 *device = 0x0405;
399 err = 0;
400 }
Chia-I Wua020bfa2011-06-13 08:48:44 +0800401 else {
Chia-I Wua020bfa2011-06-13 08:48:44 +0800402 err = -EINVAL;
403 }
404
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800405 return err;
406}
Chia-I Wua020bfa2011-06-13 08:48:44 +0800407
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800408#define DRIVER_MAP_GALLIUM_ONLY
409#include "pci_ids/pci_id_driver_map.h"
410static int pipe_find_driver(struct pipe_manager *pm, const char *name)
411{
412 int vendor, device;
413 int err;
414 const char *driver;
415
416 err = pipe_get_pci_id(pm, name, &vendor, &device);
417 if (!err) {
418 int idx;
419
420 /* look up in the driver map */
421 for (idx = 0; driver_map[idx].driver; idx++) {
422 int i;
423
424 if (vendor != driver_map[idx].vendor_id)
425 continue;
426
427 if (driver_map[idx].num_chips_ids == -1)
428 break;
429
430 for (i = 0; i < driver_map[idx].num_chips_ids; i++) {
431 if (driver_map[idx].chip_ids[i] == device)
432 break;
433 }
434 if (i < driver_map[idx].num_chips_ids)
435 break;
436 }
437
438 driver = driver_map[idx].driver;
439 err = (driver) ? 0 : -ENODEV;
440 }
441 else {
442 if (strcmp(name, "vmwgfx") == 0) {
443 driver = "vmwgfx";
444 err = 0;
445 }
446 }
447
448 if (!err)
449 strncpy(pm->driver, driver, sizeof(pm->driver) - 1);
Chia-I Wua020bfa2011-06-13 08:48:44 +0800450
451 return err;
452}
453
454struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_pipe(int fd, const char *name)
455{
456 struct pipe_manager *pm;
457
458 pm = CALLOC(1, sizeof(*pm));
459 if (!pm) {
Charles Johnsonb56dc922012-07-10 17:51:32 -0700460 ALOGE("failed to allocate pipe manager for %s", name);
Chia-I Wua020bfa2011-06-13 08:48:44 +0800461 return NULL;
462 }
463
464 pm->fd = fd;
Chia-I Wua020bfa2011-06-13 08:48:44 +0800465 pthread_mutex_init(&pm->mutex, NULL);
466
Chia-I Wu3dcc0152011-07-10 20:17:41 +0800467 if (pipe_find_driver(pm, name)) {
468 FREE(pm);
469 return NULL;
470 }
471
Chia-I Wua020bfa2011-06-13 08:48:44 +0800472 if (pipe_init_screen(pm)) {
473 FREE(pm);
474 return NULL;
475 }
476
477 pm->base.destroy = pipe_destroy;
Chia-I Wua020bfa2011-06-13 08:48:44 +0800478 pm->base.alloc = pipe_alloc;
479 pm->base.free = pipe_free;
480 pm->base.map = pipe_map;
481 pm->base.unmap = pipe_unmap;
Chia-I Wua020bfa2011-06-13 08:48:44 +0800482
483 return &pm->base;
484}