+
+destroy_bo:
+ drv_bo_destroy(bo);
+ return NULL;
+}
+
+void *drv_bo_map(struct bo *bo, const struct rectangle *rect, uint32_t map_flags,
+ struct mapping **map_data, size_t plane)
+{
+ 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->use_flags & BO_USE_PROTECTED));
+
+ 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->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;
+}
+
+int drv_bo_unmap(struct bo *bo, struct mapping *mapping)
+{
+ uint32_t i;
+ int ret = 0;
+
+ pthread_mutex_lock(&bo->drv->driver_lock);
+
+ if (--mapping->refcount)
+ goto out;
+
+ if (!--mapping->vma->refcount) {
+ ret = bo->drv->backend->bo_unmap(bo, mapping->vma);
+ free(mapping->vma);
+ }
+
+ for (i = 0; i < drv_array_size(bo->drv->mappings); i++) {
+ if (mapping == (struct mapping *)drv_array_at_idx(bo->drv->mappings, i)) {
+ drv_array_remove(bo->drv->mappings, i);
+ break;
+ }
+ }
+
+out:
+ pthread_mutex_unlock(&bo->drv->driver_lock);
+ return ret;
+}
+
+int drv_bo_invalidate(struct bo *bo, struct mapping *mapping)
+{
+ int ret = 0;
+
+ assert(mapping);
+ assert(mapping->vma);
+ assert(mapping->refcount > 0);
+ assert(mapping->vma->refcount > 0);
+
+ if (bo->drv->backend->bo_invalidate)
+ ret = bo->drv->backend->bo_invalidate(bo, mapping);
+
+ return ret;
+}
+
+int drv_bo_flush_or_unmap(struct bo *bo, struct mapping *mapping)
+{
+ int ret = 0;
+
+ assert(mapping);
+ assert(mapping->vma);
+ assert(mapping->refcount > 0);
+ assert(mapping->vma->refcount > 0);
+ assert(!(bo->use_flags & BO_USE_PROTECTED));
+
+ if (bo->drv->backend->bo_flush)
+ ret = bo->drv->backend->bo_flush(bo, mapping);
+ else
+ ret = drv_bo_unmap(bo, mapping);
+
+ return ret;