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 38struct 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 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; 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 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)) { 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 176fail: 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 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) 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 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) { 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 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); 277 buf->transfer = NULL; 278 279 pm->context->flush(pm->context, NULL, 0); 280 281 pthread_mutex_unlock(&pm->mutex); 282} 283 284static 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 309static 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> 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; 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" 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); 450 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) { 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