+ uint32_t i;
+ uint8_t *addr;
+ struct mapping mapping;
+
+ assert(rect->width >= 0);
+ assert(rect->height >= 0);
+ assert(rect->x + rect->width <= drv_bo_get_width(bo));
+ assert(rect->y + rect->height <= drv_bo_get_height(bo));
+ assert(BO_MAP_READ_WRITE & map_flags);
+ /* No CPU access for protected buffers. */
+ assert(!(bo->meta.use_flags & BO_USE_PROTECTED));
+
+ if (bo->is_test_buffer) {
+ return MAP_FAILED;
+ }
+
+ memset(&mapping, 0, sizeof(mapping));
+ mapping.rect = *rect;
+ mapping.refcount = 1;
+
+ pthread_mutex_lock(&bo->drv->driver_lock);
+
+ for (i = 0; i < drv_array_size(bo->drv->mappings); i++) {
+ struct mapping *prior = (struct mapping *)drv_array_at_idx(bo->drv->mappings, i);
+ if (prior->vma->handle != bo->handles[plane].u32 ||
+ prior->vma->map_flags != map_flags)
+ continue;
+
+ if (rect->x != prior->rect.x || rect->y != prior->rect.y ||
+ rect->width != prior->rect.width || rect->height != prior->rect.height)
+ continue;
+
+ prior->refcount++;
+ *map_data = prior;
+ goto exact_match;
+ }
+
+ for (i = 0; i < drv_array_size(bo->drv->mappings); i++) {
+ struct mapping *prior = (struct mapping *)drv_array_at_idx(bo->drv->mappings, i);
+ if (prior->vma->handle != bo->handles[plane].u32 ||
+ prior->vma->map_flags != map_flags)
+ continue;
+
+ prior->vma->refcount++;
+ mapping.vma = prior->vma;
+ goto success;
+ }
+
+ mapping.vma = calloc(1, sizeof(*mapping.vma));
+ memcpy(mapping.vma->map_strides, bo->meta.strides, sizeof(mapping.vma->map_strides));
+ addr = bo->drv->backend->bo_map(bo, mapping.vma, plane, map_flags);
+ if (addr == MAP_FAILED) {
+ *map_data = NULL;
+ free(mapping.vma);
+ pthread_mutex_unlock(&bo->drv->driver_lock);
+ return MAP_FAILED;
+ }
+
+ mapping.vma->refcount = 1;
+ mapping.vma->addr = addr;
+ mapping.vma->handle = bo->handles[plane].u32;
+ mapping.vma->map_flags = map_flags;
+
+success:
+ *map_data = drv_array_append(bo->drv->mappings, &mapping);
+exact_match:
+ drv_bo_invalidate(bo, *map_data);
+ addr = (uint8_t *)((*map_data)->vma->addr);
+ addr += drv_bo_get_plane_offset(bo, plane);
+ pthread_mutex_unlock(&bo->drv->driver_lock);
+ return (void *)addr;