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
get_pipe_format(int format)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_YV12:
78 case HAL_PIXEL_FORMAT_DRM_NV12:
79 case HAL_PIXEL_FORMAT_YCbCr_422_SP:
80 case HAL_PIXEL_FORMAT_YCrCb_420_SP:
81 default:
82 fmt = PIPE_FORMAT_NONE;
83 break;
84 }
85
86 return fmt;
87 }
88
get_pipe_bind(int usage)89 static 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
get_pipe_buffer_locked(struct pipe_manager * pm,const struct gralloc_drm_handle_t * handle)110 static 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)) {
124 ALOGE("unsupported format 0x%x", handle->format);
125 return NULL;
126 }
127
128 buf = CALLOC(1, sizeof(*buf));
129 if (!buf) {
130 ALOGE("failed to allocate pipe buffer");
131 return NULL;
132 }
133
134 templ.width0 = handle->width;
135 templ.height0 = handle->height;
136 templ.depth0 = 1;
137 templ.array_size = 1;
138
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
176 fail:
177 ALOGE("failed to allocate pipe buffer");
178 if (buf->resource)
179 pipe_resource_reference(&buf->resource, NULL);
180 FREE(buf);
181
182 return NULL;
183 }
184
pipe_alloc(struct gralloc_drm_drv_t * drv,struct gralloc_drm_handle_t * handle)185 static 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
pipe_free(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo)205 static 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)
213 pipe_transfer_unmap(pm->context, buf->transfer);
214 pipe_resource_reference(&buf->resource, NULL);
215
216 pthread_mutex_unlock(&pm->mutex);
217
218 FREE(buf);
219 }
220
pipe_map(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo,int x,int y,int w,int h,int enable_write,void ** addr)221 static 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) {
235 ALOGE("failed to create pipe context");
236 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 */
253 *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)
258 err = -ENOMEM;
259 }
260
261 pthread_mutex_unlock(&pm->mutex);
262
263 return err;
264 }
265
pipe_unmap(struct gralloc_drm_drv_t * drv,struct gralloc_drm_bo_t * bo)266 static 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);
277 buf->transfer = NULL;
278
279 pm->context->flush(pm->context, NULL, 0);
280
281 pthread_mutex_unlock(&pm->mutex);
282 }
283
pipe_destroy(struct gralloc_drm_drv_t * drv)284 static 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"
296 /* for r300 */
297 #include "radeon/drm/radeon_drm_public.h"
298 #include "r300/r300_public.h"
299 /* for r600 */
300 #include "radeon/drm/radeon_winsys.h"
301 #include "r600/r600_public.h"
302 /* for vmwgfx */
303 #include "svga/drm/svga_drm_public.h"
304 #include "svga/svga_winsys.h"
305 #include "svga/svga_public.h"
306 /* for debug */
307 #include "target-helpers/inline_debug_helper.h"
308
pipe_init_screen(struct pipe_manager * pm)309 static int pipe_init_screen(struct pipe_manager *pm)
310 {
311 struct pipe_screen *screen = NULL;
312
313 #ifdef ENABLE_PIPE_NOUVEAU
314 if (strcmp(pm->driver, "nouveau") == 0)
315 screen = nouveau_drm_screen_create(pm->fd);
316 #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) {
330 struct radeon_winsys *sws = radeon_drm_winsys_create(pm->fd);
331
332 if (sws) {
333 screen = r600_screen_create(sws);
334 if (!screen)
335 sws->destroy(sws);
336 }
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) {
353 ALOGW("failed to create screen for %s", pm->driver);
354 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>
pipe_get_pci_id(struct pipe_manager * pm,const char * name,int * vendor,int * device)365 static 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;
394 }
395 else if (strcmp(name, "vmwgfx") == 0) {
396 *vendor = 0x15ad;
397 /* assume SVGA II */
398 *device = 0x0405;
399 err = 0;
400 }
401 else {
402 err = -EINVAL;
403 }
404
405 return err;
406 }
407
408 #define DRIVER_MAP_GALLIUM_ONLY
409 #include "pci_ids/pci_id_driver_map.h"
pipe_find_driver(struct pipe_manager * pm,const char * name)410 static 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);
450
451 return err;
452 }
453
gralloc_drm_drv_create_for_pipe(int fd,const char * name)454 struct 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) {
460 ALOGE("failed to allocate pipe manager for %s", name);
461 return NULL;
462 }
463
464 pm->fd = fd;
465 pthread_mutex_init(&pm->mutex, NULL);
466
467 if (pipe_find_driver(pm, name)) {
468 FREE(pm);
469 return NULL;
470 }
471
472 if (pipe_init_screen(pm)) {
473 FREE(pm);
474 return NULL;
475 }
476
477 pm->base.destroy = pipe_destroy;
478 pm->base.alloc = pipe_alloc;
479 pm->base.free = pipe_free;
480 pm->base.map = pipe_map;
481 pm->base.unmap = pipe_unmap;
482
483 return &pm->base;
484 }
485