gralloc_drm_intel.c revision 2ec32d4f949f04d0006fff50065c904626c2e581
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 LOGE("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 LOGE("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_copy(struct gralloc_drm_drv_t *drv, 194 struct gralloc_drm_bo_t *dst, 195 struct gralloc_drm_bo_t *src, 196 short x1, short y1, short x2, short y2) 197{ 198 struct intel_info *info = (struct intel_info *) drv; 199 struct intel_buffer *dst_ib = (struct intel_buffer *) dst; 200 struct intel_buffer *src_ib = (struct intel_buffer *) src; 201 drm_intel_bo *bo_table[3]; 202 uint32_t cmd, br13, dst_pitch, src_pitch; 203 204 if (dst->handle->width != src->handle->width || 205 dst->handle->height != src->handle->height || 206 dst->handle->stride != src->handle->stride || 207 dst->handle->format != src->handle->format) { 208 LOGE("copy between incompatible buffers"); 209 return; 210 } 211 212 if (x1 < 0) 213 x1 = 0; 214 if (y1 < 0) 215 y1 = 0; 216 if (x2 > dst->handle->width) 217 x2 = dst->handle->width; 218 if (y2 > dst->handle->height) 219 y2 = dst->handle->height; 220 221 if (x2 <= x1 || y2 <= y1) 222 return; 223 224 bo_table[0] = info->batch_ibo; 225 bo_table[1] = src_ib->ibo; 226 bo_table[2] = dst_ib->ibo; 227 if (drm_intel_bufmgr_check_aperture_space(bo_table, 3)) { 228 if (batch_flush(info)) 229 return; 230 assert(!drm_intel_bufmgr_check_aperture_space(bo_table, 3)); 231 } 232 233 cmd = XY_SRC_COPY_BLT_CMD; 234 br13 = 0xcc << 16; /* ROP_S/GXcopy */ 235 dst_pitch = dst->handle->stride; 236 src_pitch = src->handle->stride; 237 238 switch (gralloc_drm_get_bpp(dst->handle->format)) { 239 case 1: 240 break; 241 case 2: 242 br13 |= (1 << 24); 243 break; 244 case 4: 245 br13 |= (1 << 24) | (1 << 25); 246 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; 247 break; 248 default: 249 LOGE("copy with unsupported format"); 250 return; 251 } 252 253 if (info->gen >= 40) { 254 if (dst_ib->tiling != I915_TILING_NONE) { 255 assert(dst_pitch % 512 == 0); 256 dst_pitch >>= 2; 257 cmd |= XY_SRC_COPY_BLT_DST_TILED; 258 } 259 if (src_ib->tiling != I915_TILING_NONE) { 260 assert(src_pitch % 512 == 0); 261 src_pitch >>= 2; 262 cmd |= XY_SRC_COPY_BLT_SRC_TILED; 263 } 264 } 265 266 if (batch_reserve(info, 8)) 267 return; 268 269 batch_dword(info, cmd); 270 batch_dword(info, br13 | dst_pitch); 271 batch_dword(info, (y1 << 16) | x1); 272 batch_dword(info, (y2 << 16) | x2); 273 batch_reloc(info, dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); 274 batch_dword(info, (y1 << 16) | x1); 275 batch_dword(info, src_pitch); 276 batch_reloc(info, src, I915_GEM_DOMAIN_RENDER, 0); 277 278 if (info->gen >= 60) { 279 batch_reserve(info, 4); 280 batch_dword(info, MI_FLUSH_DW | 2); 281 batch_dword(info, 0); 282 batch_dword(info, 0); 283 batch_dword(info, 0); 284 } 285 else { 286 int flags = (info->gen >= 40) ? 0 : 287 MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE; 288 289 batch_reserve(info, 1); 290 batch_dword(info, MI_FLUSH | flags); 291 } 292 293 batch_flush(info); 294} 295 296static drm_intel_bo *alloc_ibo(struct intel_info *info, 297 const struct gralloc_drm_handle_t *handle, 298 uint32_t *tiling, unsigned long *stride) 299{ 300 drm_intel_bo *ibo; 301 const char *name; 302 int aligned_width, aligned_height, bpp; 303 unsigned long flags; 304 305 flags = 0; 306 bpp = gralloc_drm_get_bpp(handle->format); 307 if (!bpp) { 308 LOGE("unrecognized format 0x%x", handle->format); 309 return NULL; 310 } 311 312 if (handle->usage & GRALLOC_USAGE_HW_FB) { 313 unsigned long max_stride; 314 315 max_stride = 32 * 1024; 316 if (info->gen < 50) 317 max_stride /= 2; 318 if (info->gen < 40) 319 max_stride /= 2; 320 321 name = "gralloc-fb"; 322 aligned_width = (handle->width + 63) & ~63; 323 aligned_height = handle->height; 324 flags = BO_ALLOC_FOR_RENDER; 325 326 *tiling = I915_TILING_X; 327 *stride = aligned_width * bpp; 328 if (*stride > max_stride) { 329 *tiling = I915_TILING_NONE; 330 max_stride = 32 * 1024; 331 if (*stride > max_stride) 332 return NULL; 333 } 334 335 while (1) { 336 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name, 337 aligned_width, aligned_height, 338 bpp, tiling, stride, flags); 339 if (!ibo || *stride > max_stride) { 340 if (ibo) { 341 drm_intel_bo_unreference(ibo); 342 ibo = NULL; 343 } 344 345 if (*tiling != I915_TILING_NONE) { 346 /* retry */ 347 *tiling = I915_TILING_NONE; 348 max_stride = 32 * 1024; 349 continue; 350 } 351 } 352 if (ibo) 353 drm_intel_bo_disable_reuse(ibo); 354 break; 355 } 356 } 357 else { 358 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN | 359 GRALLOC_USAGE_SW_WRITE_OFTEN)) 360 *tiling = I915_TILING_NONE; 361 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) || 362 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) && 363 handle->width >= 64)) 364 *tiling = I915_TILING_X; 365 else 366 *tiling = I915_TILING_NONE; 367 368 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) { 369 name = "gralloc-texture"; 370 /* see 2D texture layout of DRI drivers */ 371 aligned_width = (handle->width + 3) & ~3; 372 aligned_height = (handle->height + 1) & ~1; 373 } 374 else { 375 name = "gralloc-buffer"; 376 aligned_width = handle->width; 377 aligned_height = handle->height; 378 } 379 380 if (handle->usage & GRALLOC_USAGE_HW_RENDER) 381 flags = BO_ALLOC_FOR_RENDER; 382 383 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name, 384 aligned_width, aligned_height, 385 bpp, tiling, stride, flags); 386 } 387 388 return ibo; 389} 390 391static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv, 392 struct gralloc_drm_handle_t *handle) 393{ 394 struct intel_info *info = (struct intel_info *) drv; 395 struct intel_buffer *ib; 396 397 ib = calloc(1, sizeof(*ib)); 398 if (!ib) 399 return NULL; 400 401 if (handle->name) { 402 uint32_t dummy; 403 404 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr, 405 "gralloc-r", handle->name); 406 if (!ib->ibo) { 407 LOGE("failed to create ibo from name %u", 408 handle->name); 409 free(ib); 410 return NULL; 411 } 412 413 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) { 414 LOGE("failed to get ibo tiling"); 415 drm_intel_bo_unreference(ib->ibo); 416 free(ib); 417 return NULL; 418 } 419 } 420 else { 421 unsigned long stride; 422 423 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride); 424 if (!ib->ibo) { 425 LOGE("failed to allocate ibo %dx%d (format %d)", 426 handle->width, 427 handle->height, 428 handle->format); 429 free(ib); 430 return NULL; 431 } 432 433 handle->stride = stride; 434 435 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) { 436 LOGE("failed to flink ibo"); 437 drm_intel_bo_unreference(ib->ibo); 438 free(ib); 439 return NULL; 440 } 441 } 442 443 if (handle->usage & GRALLOC_USAGE_HW_FB) 444 ib->base.fb_handle = ib->ibo->handle; 445 446 ib->base.handle = handle; 447 448 return &ib->base; 449} 450 451static void intel_free(struct gralloc_drm_drv_t *drv, 452 struct gralloc_drm_bo_t *bo) 453{ 454 struct intel_buffer *ib = (struct intel_buffer *) bo; 455 456 drm_intel_bo_unreference(ib->ibo); 457 free(ib); 458} 459 460static int intel_map(struct gralloc_drm_drv_t *drv, 461 struct gralloc_drm_bo_t *bo, 462 int x, int y, int w, int h, 463 int enable_write, void **addr) 464{ 465 struct intel_buffer *ib = (struct intel_buffer *) bo; 466 int err; 467 468 if (ib->tiling != I915_TILING_NONE || 469 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB)) 470 err = drm_intel_gem_bo_map_gtt(ib->ibo); 471 else 472 err = drm_intel_bo_map(ib->ibo, enable_write); 473 if (!err) 474 *addr = ib->ibo->virtual; 475 476 return err; 477} 478 479static void intel_unmap(struct gralloc_drm_drv_t *drv, 480 struct gralloc_drm_bo_t *bo) 481{ 482 struct intel_buffer *ib = (struct intel_buffer *) bo; 483 484 if (ib->tiling != I915_TILING_NONE || 485 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB)) 486 drm_intel_gem_bo_unmap_gtt(ib->ibo); 487 else 488 drm_intel_bo_unmap(ib->ibo); 489} 490 491#include "dri/intel_chipset.h" /* for IS_965() */ 492static void intel_init_kms_features(struct gralloc_drm_drv_t *drv, 493 struct gralloc_drm_t *drm) 494{ 495 struct intel_info *info = (struct intel_info *) drv; 496 struct drm_i915_getparam gp; 497 int pageflipping, id; 498 499 drm->mode_dirty_fb = 0; 500 /* why? */ 501 drm->mode_sync_flip = 1; 502 503 memset(&gp, 0, sizeof(gp)); 504 gp.param = I915_PARAM_HAS_PAGEFLIPPING; 505 gp.value = &pageflipping; 506 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp))) 507 pageflipping = 0; 508 509 memset(&gp, 0, sizeof(gp)); 510 gp.param = I915_PARAM_CHIPSET_ID; 511 gp.value = &id; 512 if (drmCommandWriteRead(drm->fd, DRM_I915_GETPARAM, &gp, sizeof(gp))) 513 id = 0; 514 515 if (IS_965(id)) { 516 if (IS_GEN6(id)) 517 info->gen = 60; 518 else if (IS_GEN5(id)) 519 info->gen = 50; 520 else 521 info->gen = 40; 522 } 523 else { 524 info->gen = 30; 525 } 526 527 if (pageflipping && info->gen > 30) 528 drm->swap_mode = DRM_SWAP_FLIP; 529 else if (info->batch && info->gen == 30) 530 drm->swap_mode = DRM_SWAP_COPY; 531 else 532 drm->swap_mode = DRM_SWAP_SETCRTC; 533 534 if (drm->resources) { 535 int pipe; 536 537 pipe = drm_intel_get_pipe_from_crtc_id(info->bufmgr, 538 drm->crtc_id); 539 drm->swap_interval = (pipe >= 0) ? 1 : 0; 540 drm->vblank_secondary = (pipe > 0); 541 } 542 else { 543 drm->swap_interval = 0; 544 } 545} 546 547static void intel_destroy(struct gralloc_drm_drv_t *drv) 548{ 549 struct intel_info *info = (struct intel_info *) drv; 550 551 batch_destroy(info); 552 drm_intel_bufmgr_destroy(info->bufmgr); 553 free(info); 554} 555 556struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd) 557{ 558 struct intel_info *info; 559 560 info = calloc(1, sizeof(*info)); 561 if (!info) { 562 LOGE("failed to allocate driver info"); 563 return NULL; 564 } 565 566 info->fd = fd; 567 info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024); 568 if (!info->bufmgr) { 569 LOGE("failed to create buffer manager"); 570 free(info); 571 return NULL; 572 } 573 574 batch_init(info); 575 576 info->base.destroy = intel_destroy; 577 info->base.init_kms_features = intel_init_kms_features; 578 info->base.alloc = intel_alloc; 579 info->base.free = intel_free; 580 info->base.map = intel_map; 581 info->base.unmap = intel_unmap; 582 info->base.copy = intel_copy; 583 584 return &info->base; 585} 586