gralloc_drm_intel.c revision a8f0334ef5706875f2c73a2690a2f1fc3e5fee27
1/* 2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com> 3 * Copyright (C) 2010-2011 LunarG Inc. 4 * 5 * drm_gem_intel_copy is based on xorg-driver-intel, which has 6 * 7 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 8 * All Rights Reserved. 9 * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org> 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining a 12 * copy of this software and associated documentation files (the "Software"), 13 * to deal in the Software without restriction, including without limitation 14 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15 * and/or sell copies of the Software, and to permit persons to whom the 16 * Software is furnished to do so, subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be included 19 * in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 * DEALINGS IN THE SOFTWARE. 28 */ 29 30#define LOG_TAG "GRALLOC-I915" 31 32#include <cutils/log.h> 33#include <stdlib.h> 34#include <errno.h> 35#include <assert.h> 36#include <drm.h> 37#include <intel_bufmgr.h> 38#include <i915_drm.h> 39 40#include "gralloc_drm.h" 41#include "gralloc_drm_priv.h" 42 43#define MI_NOOP (0) 44#define MI_BATCH_BUFFER_END (0x0a << 23) 45#define MI_FLUSH (0x04 << 23) 46#define MI_FLUSH_DW (0x26 << 23) 47#define MI_WRITE_DIRTY_STATE (1 << 4) 48#define MI_INVALIDATE_MAP_CACHE (1 << 0) 49#define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6) 50#define XY_SRC_COPY_BLT_WRITE_ALPHA (1 << 21) 51#define XY_SRC_COPY_BLT_WRITE_RGB (1 << 20) 52#define XY_SRC_COPY_BLT_SRC_TILED (1 << 15) 53#define XY_SRC_COPY_BLT_DST_TILED (1 << 11) 54 55struct intel_info { 56 struct gralloc_drm_drv_t base; 57 58 int fd; 59 drm_intel_bufmgr *bufmgr; 60 int gen; 61 62 drm_intel_bo *batch_ibo; 63 uint32_t *batch, *cur; 64 int capacity, size; 65}; 66 67struct intel_buffer { 68 struct gralloc_drm_bo_t base; 69 drm_intel_bo *ibo; 70 uint32_t tiling; 71}; 72 73static int 74batch_next(struct intel_info *info) 75{ 76 info->cur = info->batch; 77 78 if (info->batch_ibo) 79 drm_intel_bo_unreference(info->batch_ibo); 80 81 info->batch_ibo = drm_intel_bo_alloc(info->bufmgr, 82 "gralloc-batchbuffer", info->size, 4096); 83 84 return (info->batch_ibo) ? 0 : -ENOMEM; 85} 86 87static int 88batch_count(struct intel_info *info) 89{ 90 return info->cur - info->batch; 91} 92 93static void 94batch_dword(struct intel_info *info, uint32_t dword) 95{ 96 *info->cur++ = dword; 97} 98 99static int 100batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo, 101 uint32_t read_domains, uint32_t write_domain) 102{ 103 struct intel_buffer *target = (struct intel_buffer *) bo; 104 uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]); 105 int ret; 106 107 ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset, 108 target->ibo, 0, read_domains, write_domain); 109 if (!ret) 110 batch_dword(info, target->ibo->offset); 111 112 return ret; 113} 114 115static int 116batch_flush(struct intel_info *info) 117{ 118 int size, ret; 119 120 batch_dword(info, MI_BATCH_BUFFER_END); 121 size = batch_count(info); 122 if (size & 1) { 123 batch_dword(info, MI_NOOP); 124 size = batch_count(info); 125 } 126 127 size *= sizeof(info->batch[0]); 128 ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch); 129 if (ret) { 130 ALOGE("failed to subdata batch"); 131 goto fail; 132 } 133 ret = drm_intel_bo_exec(info->batch_ibo, size, NULL, 0, 0); 134 if (ret) { 135 ALOGE("failed to exec batch"); 136 goto fail; 137 } 138 139 return batch_next(info); 140 141fail: 142 info->cur = info->batch; 143 144 return ret; 145} 146 147static int 148batch_reserve(struct intel_info *info, int count) 149{ 150 int ret = 0; 151 152 if (batch_count(info) + count > info->capacity) 153 ret = batch_flush(info); 154 155 return ret; 156} 157 158static void 159batch_destroy(struct intel_info *info) 160{ 161 if (info->batch_ibo) { 162 drm_intel_bo_unreference(info->batch_ibo); 163 info->batch_ibo = NULL; 164 } 165 166 if (info->batch) { 167 free(info->batch); 168 info->batch = NULL; 169 } 170} 171 172static int 173batch_init(struct intel_info *info) 174{ 175 int ret; 176 177 info->capacity = 512; 178 info->size = (info->capacity + 16) * sizeof(info->batch[0]); 179 180 info->batch = malloc(info->size); 181 if (!info->batch) 182 return -ENOMEM; 183 184 ret = batch_next(info); 185 if (ret) { 186 free(info->batch); 187 info->batch = NULL; 188 } 189 190 return ret; 191} 192 193static void intel_resolve_format(struct gralloc_drm_drv_t *drv, 194 struct gralloc_drm_bo_t *bo, 195 uint32_t *pitches, uint32_t *offsets, uint32_t *handles) 196{ 197 /* 198 * TODO - should take account hw specific padding, alignment 199 * for camera, video decoder etc. 200 */ 201 202 struct intel_buffer *ib = (struct intel_buffer *) bo; 203 204 memset(pitches, 0, 4 * sizeof(uint32_t)); 205 memset(offsets, 0, 4 * sizeof(uint32_t)); 206 memset(handles, 0, 4 * sizeof(uint32_t)); 207 208 pitches[0] = ib->base.handle->stride; 209 handles[0] = ib->base.fb_handle; 210 211 switch(ib->base.handle->format) { 212 case HAL_PIXEL_FORMAT_YV12: 213 214 // U and V stride are half of Y plane 215 pitches[2] = pitches[0]/2; 216 pitches[1] = pitches[0]/2; 217 218 // like I420 but U and V are in reverse order 219 offsets[2] = offsets[0] + 220 pitches[0] * ib->base.handle->height; 221 offsets[1] = offsets[2] + 222 pitches[2] * ib->base.handle->height/2; 223 224 handles[1] = handles[2] = handles[0]; 225 break; 226 227 case HAL_PIXEL_FORMAT_DRM_NV12: 228 229 // U and V are interleaved in 2nd plane 230 pitches[1] = pitches[0]; 231 offsets[1] = offsets[0] + 232 pitches[0] * ib->base.handle->height; 233 234 handles[1] = handles[0]; 235 break; 236 } 237} 238 239static void intel_copy(struct gralloc_drm_drv_t *drv, 240 struct gralloc_drm_bo_t *dst, 241 struct gralloc_drm_bo_t *src, 242 short x1, short y1, short x2, short y2) 243{ 244 struct intel_info *info = (struct intel_info *) drv; 245 struct intel_buffer *dst_ib = (struct intel_buffer *) dst; 246 struct intel_buffer *src_ib = (struct intel_buffer *) src; 247 drm_intel_bo *bo_table[3]; 248 uint32_t cmd, br13, dst_pitch, src_pitch; 249 250 if (dst->handle->width != src->handle->width || 251 dst->handle->height != src->handle->height || 252 dst->handle->stride != src->handle->stride || 253 dst->handle->format != src->handle->format) { 254 ALOGE("copy between incompatible buffers"); 255 return; 256 } 257 258 if (x1 < 0) 259 x1 = 0; 260 if (y1 < 0) 261 y1 = 0; 262 if (x2 > dst->handle->width) 263 x2 = dst->handle->width; 264 if (y2 > dst->handle->height) 265 y2 = dst->handle->height; 266 267 if (x2 <= x1 || y2 <= y1) 268 return; 269 270 bo_table[0] = info->batch_ibo; 271 bo_table[1] = src_ib->ibo; 272 bo_table[2] = dst_ib->ibo; 273 if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) { 274 if (batch_flush(info)) 275 return; 276 assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3)); 277 } 278 279 cmd = XY_SRC_COPY_BLT_CMD; 280 br13 = 0xcc << 16; /* ROP_S/GXcopy */ 281 dst_pitch = dst->handle->stride; 282 src_pitch = src->handle->stride; 283 284 switch (gralloc_drm_get_bpp(dst->handle->format)) { 285 case 1: 286 break; 287 case 2: 288 br13 |= (1 << 24); 289 break; 290 case 4: 291 br13 |= (1 << 24) | (1 << 25); 292 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; 293 break; 294 default: 295 ALOGE("copy with unsupported format"); 296 return; 297 } 298 299 if (info->gen >= 40) { 300 if (dst_ib->tiling != I915_TILING_NONE) { 301 assert(dst_pitch % 512 == 0); 302 dst_pitch >>= 2; 303 cmd |= XY_SRC_COPY_BLT_DST_TILED; 304 } 305 if (src_ib->tiling != I915_TILING_NONE) { 306 assert(src_pitch % 512 == 0); 307 src_pitch >>= 2; 308 cmd |= XY_SRC_COPY_BLT_SRC_TILED; 309 } 310 } 311 312 if (batch_reserve(info, 8)) 313 return; 314 315 batch_dword(info, cmd); 316 batch_dword(info, br13 | dst_pitch); 317 batch_dword(info, (y1 << 16) | x1); 318 batch_dword(info, (y2 << 16) | x2); 319 batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); 320 batch_dword(info, (y1 << 16) | x1); 321 batch_dword(info, src_pitch); 322 batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0); 323 324 if (info->gen >= 60) { 325 batch_reserve(info, 4); 326 batch_dword(info, MI_FLUSH_DW | 2); 327 batch_dword(info, 0); 328 batch_dword(info, 0); 329 batch_dword(info, 0); 330 } 331 else { 332 int flags = (info->gen >= 40) ? 0 : 333 MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE; 334 335 batch_reserve(info, 1); 336 batch_dword(info, MI_FLUSH | flags); 337 } 338 339 batch_flush(info); 340} 341 342static drm_intel_bo *alloc_ibo(struct intel_info *info, 343 const struct gralloc_drm_handle_t *handle, 344 uint32_t *tiling, unsigned long *stride) 345{ 346 drm_intel_bo *ibo; 347 const char *name; 348 int aligned_width, aligned_height, bpp; 349 unsigned long flags; 350 351 flags = 0; 352 bpp = gralloc_drm_get_bpp(handle->format); 353 if (!bpp) { 354 ALOGE("unrecognized format 0x%x", handle->format); 355 return NULL; 356 } 357 358 aligned_width = handle->width; 359 aligned_height = handle->height; 360 gralloc_drm_align_geometry(handle->format, 361 &aligned_width, &aligned_height); 362 363 if (handle->usage & GRALLOC_USAGE_HW_FB) { 364 unsigned long max_stride; 365 366 max_stride = 32 * 1024; 367 if (info->gen < 50) 368 max_stride /= 2; 369 if (info->gen < 40) 370 max_stride /= 2; 371 372 name = "gralloc-fb"; 373 aligned_width = (aligned_width + 63) & ~63; 374 flags = BO_ALLOC_FOR_RENDER; 375 376 *tiling = I915_TILING_X; 377 *stride = aligned_width * bpp; 378 if (*stride > max_stride) { 379 *tiling = I915_TILING_NONE; 380 max_stride = 32 * 1024; 381 if (*stride > max_stride) 382 return NULL; 383 } 384 385 while (1) { 386 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name, 387 aligned_width, aligned_height, 388 bpp, tiling, stride, flags); 389 if (!ibo || *stride > max_stride) { 390 if (ibo) { 391 drm_intel_bo_unreference(ibo); 392 ibo = NULL; 393 } 394 395 if (*tiling != I915_TILING_NONE) { 396 /* retry */ 397 *tiling = I915_TILING_NONE; 398 max_stride = 32 * 1024; 399 continue; 400 } 401 } 402 if (ibo) 403 drm_intel_bo_disable_reuse(ibo); 404 break; 405 } 406 } 407 else { 408 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN | 409 GRALLOC_USAGE_SW_WRITE_OFTEN)) 410 *tiling = I915_TILING_NONE; 411 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) || 412 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) && 413 handle->width >= 64)) 414 *tiling = I915_TILING_X; 415 else 416 *tiling = I915_TILING_NONE; 417 418 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) { 419 name = "gralloc-texture"; 420 /* see 2D texture layout of DRI drivers */ 421 aligned_width = (aligned_width + 3) & ~3; 422 aligned_height = (aligned_height + 1) & ~1; 423 } 424 else { 425 name = "gralloc-buffer"; 426 } 427 428 if (handle->usage & GRALLOC_USAGE_HW_RENDER) 429 flags = BO_ALLOC_FOR_RENDER; 430 431 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name, 432 aligned_width, aligned_height, 433 bpp, tiling, stride, flags); 434 } 435 436 return ibo; 437} 438 439static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv, 440 struct gralloc_drm_handle_t *handle) 441{ 442 struct intel_info *info = (struct intel_info *) drv; 443 struct intel_buffer *ib; 444 445 ib = calloc(1, sizeof(*ib)); 446 if (!ib) 447 return NULL; 448 449 if (handle->name) { 450 uint32_t dummy; 451 452 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr, 453 "gralloc-r", handle->name); 454 if (!ib->ibo) { 455 ALOGE("failed to create ibo from name %u", 456 handle->name); 457 free(ib); 458 return NULL; 459 } 460 461 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) { 462 ALOGE("failed to get ibo tiling"); 463 drm_intel_bo_unreference(ib->ibo); 464 free(ib); 465 return NULL; 466 } 467 } 468 else { 469 unsigned long stride; 470 471 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride); 472 if (!ib->ibo) { 473 ALOGE("failed to allocate ibo %dx%d (format %d)", 474 handle->width, 475 handle->height, 476 handle->format); 477 free(ib); 478 return NULL; 479 } 480 481 handle->stride = stride; 482 483 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) { 484 ALOGE("failed to flink ibo"); 485 drm_intel_bo_unreference(ib->ibo); 486 free(ib); 487 return NULL; 488 } 489 } 490 491 ib->base.fb_handle = ib->ibo->handle; 492 493 ib->base.handle = handle; 494 495 return &ib->base; 496} 497 498static void intel_free(struct gralloc_drm_drv_t *drv, 499 struct gralloc_drm_bo_t *bo) 500{ 501 struct intel_buffer *ib = (struct intel_buffer *) bo; 502 503 drm_intel_bo_unreference(ib->ibo); 504 free(ib); 505} 506 507static int intel_map(struct gralloc_drm_drv_t *drv, 508 struct gralloc_drm_bo_t *bo, 509 int x, int y, int w, int h, 510 int enable_write, void **addr) 511{ 512 struct intel_buffer *ib = (struct intel_buffer *) bo; 513 int err; 514 515 if (ib->tiling != I915_TILING_NONE || 516 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB)) 517 err = drm_intel_gem_bo_map_gtt(ib->ibo); 518 else 519 err = drm_intel_bo_map(ib->ibo, enable_write); 520 if (!err) 521 *addr = ib->ibo->virtual; 522 523 return err; 524} 525 526static void intel_unmap(struct gralloc_drm_drv_t *drv, 527 struct gralloc_drm_bo_t *bo) 528{ 529 struct intel_buffer *ib = (struct intel_buffer *) bo; 530 531 if (ib->tiling != I915_TILING_NONE || 532 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB)) 533 drm_intel_gem_bo_unmap_gtt(ib->ibo); 534 else 535 drm_intel_bo_unmap(ib->ibo); 536} 537 538#include "intel_chipset.h" /* for platform detection macros */ 539static void intel_init_kms_features(struct gralloc_drm_drv_t *drv, 540 struct gralloc_drm_t *drm) 541{ 542 struct intel_info *info = (struct intel_info *) drv; 543 struct drm_i915_getparam gp; 544 int pageflipping, id; 545 546 switch (drm->primary.fb_format) { 547 case HAL_PIXEL_FORMAT_BGRA_8888: 548 case HAL_PIXEL_FORMAT_RGB_565: 549 break; 550 default: 551 drm->primary.fb_format = HAL_PIXEL_FORMAT_BGRA_8888; 552 break; 553 } 554 555 drm->mode_quirk_vmwgfx = 0; 556 /* why? */ 557 drm->mode_sync_flip = 1; 558 559 memset(&gp, 0, sizeof(gp)); 560 gp.param = I915_PARAM_HAS_PAGEFLIPPING; 561 gp.value = &pageflipping; 562 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp))) 563 pageflipping = 0; 564 565 memset(&gp, 0, sizeof(gp)); 566 gp.param = I915_PARAM_CHIPSET_ID; 567 gp.value = &id; 568 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp))) 569 id = 0; 570 571 /* GEN4, G4X, GEN5, GEN6, GEN7 */ 572 if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) { 573 if (IS_GEN7(id)) 574 info->gen = 70; 575 else if (IS_GEN6(id)) 576 info->gen = 60; 577 else if (IS_GEN5(id)) 578 info->gen = 50; 579 else 580 info->gen = 40; 581 } 582 else { 583 info->gen = 30; 584 } 585 586 if (pageflipping && info->gen > 30) 587 drm->swap_mode = DRM_SWAP_FLIP; 588 else if (info->batch && info->gen == 30) 589 drm->swap_mode = DRM_SWAP_COPY; 590 else 591 drm->swap_mode = DRM_SWAP_SETCRTC; 592 593 if (drm->resources) { 594 int pipe; 595 596 pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr, 597 drm->primary.crtc_id); 598 drm->swap_interval = (pipe >= 0) ? 1 : 0; 599 drm->vblank_secondary = (pipe > 0); 600 } 601 else { 602 drm->swap_interval = 0; 603 } 604} 605 606static void intel_destroy(struct gralloc_drm_drv_t *drv) 607{ 608 struct intel_info *info = (struct intel_info *) drv; 609 610 batch_destroy(info); 611 drm_intel_bufmgr_destroy(info->bufmgr); 612 free(info); 613} 614 615struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd) 616{ 617 struct intel_info *info; 618 619 info = calloc(1, sizeof(*info)); 620 if (!info) { 621 ALOGE("failed to allocate driver info"); 622 return NULL; 623 } 624 625 info->fd = fd; 626 info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024); 627 if (!info->bufmgr) { 628 ALOGE("failed to create buffer manager"); 629 free(info); 630 return NULL; 631 } 632 633 batch_init(info); 634 635 info->base.destroy = intel_destroy; 636 info->base.init_kms_features = intel_init_kms_features; 637 info->base.alloc = intel_alloc; 638 info->base.free = intel_free; 639 info->base.map = intel_map; 640 info->base.unmap = intel_unmap; 641 info->base.copy = intel_copy; 642 info->base.resolve_format = intel_resolve_format; 643 644 return &info->base; 645} 646