1 /* 2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe (at) 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 (at) 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 55 struct 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 int exec_blt; 66 }; 67 68 struct intel_buffer { 69 struct gralloc_drm_bo_t base; 70 drm_intel_bo *ibo; 71 uint32_t tiling; 72 }; 73 74 static int 75 batch_next(struct intel_info *info) 76 { 77 info->cur = info->batch; 78 79 if (info->batch_ibo) 80 drm_intel_bo_unreference(info->batch_ibo); 81 82 info->batch_ibo = drm_intel_bo_alloc(info->bufmgr, 83 "gralloc-batchbuffer", info->size, 4096); 84 85 return (info->batch_ibo) ? 0 : -ENOMEM; 86 } 87 88 static int 89 batch_count(struct intel_info *info) 90 { 91 return info->cur - info->batch; 92 } 93 94 static void 95 batch_dword(struct intel_info *info, uint32_t dword) 96 { 97 *info->cur++ = dword; 98 } 99 100 static int 101 batch_reloc(struct intel_info *info, struct gralloc_drm_bo_t *bo, 102 uint32_t read_domains, uint32_t write_domain) 103 { 104 struct intel_buffer *target = (struct intel_buffer *) bo; 105 uint32_t offset = (info->cur - info->batch) * sizeof(info->batch[0]); 106 int ret; 107 108 ret = drm_intel_bo_emit_reloc(info->batch_ibo, offset, 109 target->ibo, 0, read_domains, write_domain); 110 if (!ret) 111 batch_dword(info, target->ibo->offset); 112 113 return ret; 114 } 115 116 static int 117 batch_flush(struct intel_info *info) 118 { 119 int size, ret; 120 121 batch_dword(info, MI_BATCH_BUFFER_END); 122 size = batch_count(info); 123 if (size & 1) { 124 batch_dword(info, MI_NOOP); 125 size = batch_count(info); 126 } 127 128 size *= sizeof(info->batch[0]); 129 ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch); 130 if (ret) { 131 ALOGE("failed to subdata batch"); 132 goto fail; 133 } 134 ret = drm_intel_bo_mrb_exec(info->batch_ibo, size, 135 NULL, 0, 0, info->exec_blt); 136 if (ret) { 137 ALOGE("failed to exec batch"); 138 goto fail; 139 } 140 141 return batch_next(info); 142 143 fail: 144 info->cur = info->batch; 145 146 return ret; 147 } 148 149 static int 150 batch_reserve(struct intel_info *info, int count) 151 { 152 int ret = 0; 153 154 if (batch_count(info) + count > info->capacity) 155 ret = batch_flush(info); 156 157 return ret; 158 } 159 160 static void 161 batch_destroy(struct intel_info *info) 162 { 163 if (info->batch_ibo) { 164 drm_intel_bo_unreference(info->batch_ibo); 165 info->batch_ibo = NULL; 166 } 167 168 if (info->batch) { 169 free(info->batch); 170 info->batch = NULL; 171 } 172 } 173 174 static int 175 batch_init(struct intel_info *info) 176 { 177 int ret; 178 179 info->capacity = 512; 180 info->size = (info->capacity + 16) * sizeof(info->batch[0]); 181 182 info->batch = malloc(info->size); 183 if (!info->batch) 184 return -ENOMEM; 185 186 ret = batch_next(info); 187 if (ret) { 188 free(info->batch); 189 info->batch = NULL; 190 } 191 192 return ret; 193 } 194 195 static void intel_resolve_format(struct gralloc_drm_drv_t *drv, 196 struct gralloc_drm_bo_t *bo, 197 uint32_t *pitches, uint32_t *offsets, uint32_t *handles) 198 { 199 /* 200 * TODO - should take account hw specific padding, alignment 201 * for camera, video decoder etc. 202 */ 203 204 struct intel_buffer *ib = (struct intel_buffer *) bo; 205 206 memset(pitches, 0, 4 * sizeof(uint32_t)); 207 memset(offsets, 0, 4 * sizeof(uint32_t)); 208 memset(handles, 0, 4 * sizeof(uint32_t)); 209 210 pitches[0] = ib->base.handle->stride; 211 handles[0] = ib->base.fb_handle; 212 213 switch(ib->base.handle->format) { 214 case HAL_PIXEL_FORMAT_YV12: 215 216 // U and V stride are half of Y plane 217 pitches[2] = pitches[0]/2; 218 pitches[1] = pitches[0]/2; 219 220 // like I420 but U and V are in reverse order 221 offsets[2] = offsets[0] + 222 pitches[0] * ib->base.handle->height; 223 offsets[1] = offsets[2] + 224 pitches[2] * ib->base.handle->height/2; 225 226 handles[1] = handles[2] = handles[0]; 227 break; 228 229 case HAL_PIXEL_FORMAT_DRM_NV12: 230 231 // U and V are interleaved in 2nd plane 232 pitches[1] = pitches[0]; 233 offsets[1] = offsets[0] + 234 pitches[0] * ib->base.handle->height; 235 236 handles[1] = handles[0]; 237 break; 238 } 239 } 240 241 static drm_intel_bo *alloc_ibo(struct intel_info *info, 242 const struct gralloc_drm_handle_t *handle, 243 uint32_t *tiling, unsigned long *stride) 244 { 245 drm_intel_bo *ibo; 246 const char *name; 247 int aligned_width, aligned_height, bpp; 248 unsigned long flags; 249 250 flags = 0; 251 bpp = gralloc_drm_get_bpp(handle->format); 252 if (!bpp) { 253 ALOGE("unrecognized format 0x%x", handle->format); 254 return NULL; 255 } 256 257 aligned_width = handle->width; 258 aligned_height = handle->height; 259 gralloc_drm_align_geometry(handle->format, 260 &aligned_width, &aligned_height); 261 262 if (handle->usage & GRALLOC_USAGE_HW_FB) { 263 unsigned long max_stride; 264 265 max_stride = 32 * 1024; 266 if (info->gen < 50) 267 max_stride /= 2; 268 if (info->gen < 40) 269 max_stride /= 2; 270 271 name = "gralloc-fb"; 272 aligned_width = ALIGN(aligned_width, 64); 273 flags = BO_ALLOC_FOR_RENDER; 274 275 *tiling = I915_TILING_X; 276 *stride = aligned_width * bpp; 277 if (*stride > max_stride) { 278 *tiling = I915_TILING_NONE; 279 max_stride = 32 * 1024; 280 if (*stride > max_stride) 281 return NULL; 282 } 283 284 while (1) { 285 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name, 286 aligned_width, aligned_height, 287 bpp, tiling, stride, flags); 288 if (!ibo || *stride > max_stride) { 289 if (ibo) { 290 drm_intel_bo_unreference(ibo); 291 ibo = NULL; 292 } 293 294 if (*tiling != I915_TILING_NONE) { 295 /* retry */ 296 *tiling = I915_TILING_NONE; 297 max_stride = 32 * 1024; 298 continue; 299 } 300 } 301 if (ibo) 302 drm_intel_bo_disable_reuse(ibo); 303 break; 304 } 305 } 306 else { 307 if (handle->usage & (GRALLOC_USAGE_SW_READ_OFTEN | 308 GRALLOC_USAGE_SW_WRITE_OFTEN)) 309 *tiling = I915_TILING_NONE; 310 else if ((handle->usage & GRALLOC_USAGE_HW_RENDER) || 311 ((handle->usage & GRALLOC_USAGE_HW_TEXTURE) && 312 handle->width >= 64)) 313 *tiling = I915_TILING_X; 314 else 315 *tiling = I915_TILING_NONE; 316 317 if (handle->usage & GRALLOC_USAGE_HW_TEXTURE) { 318 name = "gralloc-texture"; 319 /* see 2D texture layout of DRI drivers */ 320 aligned_width = ALIGN(aligned_width, 4); 321 aligned_height = ALIGN(aligned_height, 2); 322 } 323 else { 324 name = "gralloc-buffer"; 325 } 326 327 if (handle->usage & GRALLOC_USAGE_HW_RENDER) 328 flags = BO_ALLOC_FOR_RENDER; 329 330 ibo = drm_intel_bo_alloc_tiled(info->bufmgr, name, 331 aligned_width, aligned_height, 332 bpp, tiling, stride, flags); 333 } 334 335 return ibo; 336 } 337 338 static struct gralloc_drm_bo_t *intel_alloc(struct gralloc_drm_drv_t *drv, 339 struct gralloc_drm_handle_t *handle) 340 { 341 struct intel_info *info = (struct intel_info *) drv; 342 struct intel_buffer *ib; 343 344 ib = calloc(1, sizeof(*ib)); 345 if (!ib) 346 return NULL; 347 348 if (handle->name) { 349 uint32_t dummy; 350 351 ib->ibo = drm_intel_bo_gem_create_from_name(info->bufmgr, 352 "gralloc-r", handle->name); 353 if (!ib->ibo) { 354 ALOGE("failed to create ibo from name %u", 355 handle->name); 356 free(ib); 357 return NULL; 358 } 359 360 if (drm_intel_bo_get_tiling(ib->ibo, &ib->tiling, &dummy)) { 361 ALOGE("failed to get ibo tiling"); 362 drm_intel_bo_unreference(ib->ibo); 363 free(ib); 364 return NULL; 365 } 366 } 367 else { 368 unsigned long stride; 369 370 ib->ibo = alloc_ibo(info, handle, &ib->tiling, &stride); 371 if (!ib->ibo) { 372 ALOGE("failed to allocate ibo %dx%d (format %d)", 373 handle->width, 374 handle->height, 375 handle->format); 376 free(ib); 377 return NULL; 378 } 379 380 handle->stride = stride; 381 382 if (drm_intel_bo_flink(ib->ibo, (uint32_t *) &handle->name)) { 383 ALOGE("failed to flink ibo"); 384 drm_intel_bo_unreference(ib->ibo); 385 free(ib); 386 return NULL; 387 } 388 } 389 390 ib->base.fb_handle = ib->ibo->handle; 391 392 ib->base.handle = handle; 393 394 return &ib->base; 395 } 396 397 static void intel_free(struct gralloc_drm_drv_t *drv, 398 struct gralloc_drm_bo_t *bo) 399 { 400 struct intel_buffer *ib = (struct intel_buffer *) bo; 401 402 drm_intel_bo_unreference(ib->ibo); 403 free(ib); 404 } 405 406 static int intel_map(struct gralloc_drm_drv_t *drv, 407 struct gralloc_drm_bo_t *bo, 408 int x, int y, int w, int h, 409 int enable_write, void **addr) 410 { 411 struct intel_buffer *ib = (struct intel_buffer *) bo; 412 int err; 413 414 if (ib->tiling != I915_TILING_NONE || 415 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB)) 416 err = drm_intel_gem_bo_map_gtt(ib->ibo); 417 else 418 err = drm_intel_bo_map(ib->ibo, enable_write); 419 if (!err) 420 *addr = ib->ibo->virtual; 421 422 return err; 423 } 424 425 static void intel_unmap(struct gralloc_drm_drv_t *drv, 426 struct gralloc_drm_bo_t *bo) 427 { 428 struct intel_buffer *ib = (struct intel_buffer *) bo; 429 430 if (ib->tiling != I915_TILING_NONE || 431 (ib->base.handle->usage & GRALLOC_USAGE_HW_FB)) 432 drm_intel_gem_bo_unmap_gtt(ib->ibo); 433 else 434 drm_intel_bo_unmap(ib->ibo); 435 } 436 437 #include "intel_chipset.h" /* for platform detection macros */ 438 static void gen_init(struct intel_info *info) 439 { 440 struct drm_i915_getparam gp; 441 int pageflipping, id, has_blt; 442 443 memset(&gp, 0, sizeof(gp)); 444 gp.param = I915_PARAM_CHIPSET_ID; 445 gp.value = &id; 446 if (drmCommandWriteRead(info->fd, DRM_I915_GETPARAM, &gp, sizeof(gp))) 447 id = 0; 448 449 memset(&gp, 0, sizeof(gp)); 450 gp.param = I915_PARAM_HAS_BLT; 451 gp.value = &has_blt; 452 if (drmCommandWriteRead(info->fd, DRM_I915_GETPARAM, &gp, sizeof(gp))) 453 has_blt = 0; 454 info->exec_blt = has_blt ? I915_EXEC_BLT : 0; 455 456 /* GEN4, G4X, GEN5, GEN6, GEN7 */ 457 if ((IS_9XX(id) || IS_G4X(id)) && !IS_GEN3(id)) { 458 if (IS_GEN7(id)) 459 info->gen = 70; 460 else if (IS_GEN6(id)) 461 info->gen = 60; 462 else if (IS_GEN5(id)) 463 info->gen = 50; 464 else 465 info->gen = 40; 466 } 467 else { 468 info->gen = 30; 469 } 470 } 471 472 static void intel_destroy(struct gralloc_drm_drv_t *drv) 473 { 474 struct intel_info *info = (struct intel_info *) drv; 475 476 batch_destroy(info); 477 drm_intel_bufmgr_destroy(info->bufmgr); 478 free(info); 479 } 480 481 struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_intel(int fd) 482 { 483 struct intel_info *info; 484 485 info = calloc(1, sizeof(*info)); 486 if (!info) { 487 ALOGE("failed to allocate driver info"); 488 return NULL; 489 } 490 491 info->fd = fd; 492 info->bufmgr = drm_intel_bufmgr_gem_init(info->fd, 16 * 1024); 493 if (!info->bufmgr) { 494 ALOGE("failed to create buffer manager"); 495 free(info); 496 return NULL; 497 } 498 499 batch_init(info); 500 gen_init(info); 501 502 info->base.destroy = intel_destroy; 503 info->base.alloc = intel_alloc; 504 info->base.free = intel_free; 505 info->base.map = intel_map; 506 info->base.unmap = intel_unmap; 507 info->base.resolve_format = intel_resolve_format; 508 509 return &info->base; 510 } 511