#ifdef DRV_I915
+#include <assert.h>
#include <errno.h>
#include <i915_drm.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#define I915_CACHELINE_MASK (I915_CACHELINE_SIZE - 1)
static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB1555,
- DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565,
- DRM_FORMAT_XBGR2101010, DRM_FORMAT_XBGR8888,
- DRM_FORMAT_XRGB1555, DRM_FORMAT_XRGB2101010,
- DRM_FORMAT_XRGB8888 };
+ DRM_FORMAT_ARGB8888, DRM_FORMAT_BGR888,
+ DRM_FORMAT_RGB565, DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_XRGB2101010, DRM_FORMAT_XRGB8888 };
-static const uint32_t tileable_texture_source_formats[] = { DRM_FORMAT_GR88, DRM_FORMAT_NV12,
- DRM_FORMAT_R8, DRM_FORMAT_UYVY,
- DRM_FORMAT_YUYV };
+static const uint32_t tileable_texture_source_formats[] = { DRM_FORMAT_GR88, DRM_FORMAT_R8,
+ DRM_FORMAT_UYVY, DRM_FORMAT_YUYV };
-static const uint32_t texture_source_formats[] = { DRM_FORMAT_YVU420, DRM_FORMAT_YVU420_ANDROID };
+static const uint32_t texture_source_formats[] = { DRM_FORMAT_YVU420, DRM_FORMAT_YVU420_ANDROID,
+ DRM_FORMAT_NV12 };
struct i915_device {
uint32_t gen;
return 4;
}
+/*
+ * We allow allocation of ARGB formats for SCANOUT if the corresponding XRGB
+ * formats supports it. It's up to the caller (chrome ozone) to ultimately not
+ * scan out ARGB if the display controller only supports XRGB, but we'll allow
+ * the allocation of the bo here.
+ */
+static bool format_compatible(const struct combination *combo, uint32_t format)
+{
+ if (combo->format == format)
+ return true;
+
+ switch (format) {
+ case DRM_FORMAT_XRGB8888:
+ return combo->format == DRM_FORMAT_ARGB8888;
+ case DRM_FORMAT_XBGR8888:
+ return combo->format == DRM_FORMAT_ABGR8888;
+ case DRM_FORMAT_RGBX8888:
+ return combo->format == DRM_FORMAT_RGBA8888;
+ case DRM_FORMAT_BGRX8888:
+ return combo->format == DRM_FORMAT_BGRA8888;
+ default:
+ return false;
+ }
+}
+
static int i915_add_kms_item(struct driver *drv, const struct kms_item *item)
{
uint32_t i;
* Older hardware can't scanout Y-tiled formats. Newer devices can, and
* report this functionality via format modifiers.
*/
- for (i = 0; i < drv->combos.size; i++) {
- combo = &drv->combos.data[i];
- if (combo->format != item->format)
+ for (i = 0; i < drv_array_size(drv->combos); i++) {
+ combo = (struct combination *)drv_array_at_idx(drv->combos, i);
+ if (!format_compatible(combo, item->format))
continue;
- if (item->modifier == DRM_FORMAT_MOD_INVALID &&
+ if (item->modifier == DRM_FORMAT_MOD_LINEAR &&
combo->metadata.tiling == I915_TILING_X) {
/*
* FIXME: drv_query_kms() does not report the available modifiers
combo->use_flags |= item->use_flags & ~BO_USE_CURSOR;
}
+ /* If we can scanout NV12, we support all tiling modes. */
+ if (item->format == DRM_FORMAT_NV12)
+ combo->use_flags |= item->use_flags;
+
if (combo->metadata.modifier == item->modifier)
combo->use_flags |= item->use_flags;
}
static int i915_add_combinations(struct driver *drv)
{
int ret;
- uint32_t i, num_items;
- struct kms_item *items;
+ uint32_t i;
+ struct drv_array *kms_items;
struct format_metadata metadata;
uint64_t render_use_flags, texture_use_flags;
metadata.priority = 1;
metadata.modifier = DRM_FORMAT_MOD_LINEAR;
- ret = drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
- &metadata, render_use_flags);
- if (ret)
- return ret;
+ drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
+ &metadata, render_use_flags);
- ret = drv_add_combinations(drv, texture_source_formats, ARRAY_SIZE(texture_source_formats),
- &metadata, texture_use_flags);
- if (ret)
- return ret;
+ drv_add_combinations(drv, texture_source_formats, ARRAY_SIZE(texture_source_formats),
+ &metadata, texture_use_flags);
- ret = drv_add_combinations(drv, tileable_texture_source_formats,
- ARRAY_SIZE(tileable_texture_source_formats), &metadata,
- texture_use_flags);
- if (ret)
- return ret;
+ drv_add_combinations(drv, tileable_texture_source_formats,
+ ARRAY_SIZE(tileable_texture_source_formats), &metadata,
+ texture_use_flags);
drv_modify_combination(drv, DRM_FORMAT_XRGB8888, &metadata, BO_USE_CURSOR | BO_USE_SCANOUT);
drv_modify_combination(drv, DRM_FORMAT_ARGB8888, &metadata, BO_USE_CURSOR | BO_USE_SCANOUT);
metadata.priority = 2;
metadata.modifier = I915_FORMAT_MOD_X_TILED;
- ret = drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
- &metadata, render_use_flags);
- if (ret)
- return ret;
+ drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
+ &metadata, render_use_flags);
- ret = drv_add_combinations(drv, tileable_texture_source_formats,
- ARRAY_SIZE(tileable_texture_source_formats), &metadata,
- texture_use_flags);
- if (ret)
- return ret;
+ drv_add_combinations(drv, tileable_texture_source_formats,
+ ARRAY_SIZE(tileable_texture_source_formats), &metadata,
+ texture_use_flags);
metadata.tiling = I915_TILING_Y;
metadata.priority = 3;
metadata.modifier = I915_FORMAT_MOD_Y_TILED;
- ret = drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
- &metadata, render_use_flags);
- if (ret)
- return ret;
+ drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
+ &metadata, render_use_flags);
- ret = drv_add_combinations(drv, tileable_texture_source_formats,
- ARRAY_SIZE(tileable_texture_source_formats), &metadata,
- texture_use_flags);
- if (ret)
- return ret;
+ drv_add_combinations(drv, tileable_texture_source_formats,
+ ARRAY_SIZE(tileable_texture_source_formats), &metadata,
+ texture_use_flags);
- items = drv_query_kms(drv, &num_items);
- if (!items || !num_items)
+ /* Support y-tiled NV12 for libva */
+ const uint32_t nv12_format = DRM_FORMAT_NV12;
+ drv_add_combinations(drv, &nv12_format, 1, &metadata,
+ BO_USE_TEXTURE | BO_USE_HW_VIDEO_DECODER);
+
+ kms_items = drv_query_kms(drv);
+ if (!kms_items)
return 0;
- for (i = 0; i < num_items; i++) {
- ret = i915_add_kms_item(drv, &items[i]);
+ for (i = 0; i < drv_array_size(kms_items); i++) {
+ ret = i915_add_kms_item(drv, (struct kms_item *)drv_array_at_idx(kms_items, i));
if (ret) {
- free(items);
+ drv_array_destroy(kms_items);
return ret;
}
}
- free(items);
+ drv_array_destroy(kms_items);
return 0;
}
uint32_t *aligned_height)
{
struct i915_device *i915 = bo->drv->priv;
- uint32_t horizontal_alignment = 4;
- uint32_t vertical_alignment = 4;
+ uint32_t horizontal_alignment;
+ uint32_t vertical_alignment;
switch (tiling) {
default:
case I915_TILING_NONE:
+ /*
+ * The Intel GPU doesn't need any alignment in linear mode,
+ * but libva requires the allocation stride to be aligned to
+ * 16 bytes and height to 4 rows. Further, we round up the
+ * horizontal alignment so that row start on a cache line (64
+ * bytes).
+ */
horizontal_alignment = 64;
+ vertical_alignment = 4;
break;
case I915_TILING_X:
break;
}
- /*
- * The alignment calculated above is based on the full size luma plane and to have chroma
- * planes properly aligned with subsampled formats, we need to multiply luma alignment by
- * subsampling factor.
- */
- switch (bo->format) {
- case DRM_FORMAT_YVU420_ANDROID:
- case DRM_FORMAT_YVU420:
- horizontal_alignment *= 2;
- /* Fall through */
- case DRM_FORMAT_NV12:
- vertical_alignment *= 2;
- break;
- }
-
*aligned_height = ALIGN(bo->height, vertical_alignment);
if (i915->gen > 3) {
*stride = ALIGN(*stride, horizontal_alignment);
get_param.value = &device_id;
ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
if (ret) {
- fprintf(stderr, "drv: Failed to get I915_PARAM_CHIPSET_ID\n");
+ drv_log("Failed to get I915_PARAM_CHIPSET_ID\n");
free(i915);
return -EINVAL;
}
get_param.value = &i915->has_llc;
ret = drmIoctl(drv->fd, DRM_IOCTL_I915_GETPARAM, &get_param);
if (ret) {
- fprintf(stderr, "drv: Failed to get I915_PARAM_HAS_LLC\n");
+ drv_log("Failed to get I915_PARAM_HAS_LLC\n");
free(i915);
return -EINVAL;
}
return i915_add_combinations(drv);
}
+static int i915_bo_from_format(struct bo *bo, uint32_t width, uint32_t height, uint32_t format)
+{
+ uint32_t offset;
+ size_t plane;
+ int ret;
+
+ offset = 0;
+ for (plane = 0; plane < drv_num_planes_from_format(format); plane++) {
+ uint32_t stride = drv_stride_from_format(format, width, plane);
+ uint32_t plane_height = drv_height_from_format(format, height, plane);
+
+ if (bo->tiling != I915_TILING_NONE)
+ assert(IS_ALIGNED(offset, 4096));
+
+ ret = i915_align_dimensions(bo, bo->tiling, &stride, &plane_height);
+ if (ret)
+ return ret;
+
+ bo->strides[plane] = stride;
+ bo->sizes[plane] = stride * plane_height;
+ bo->offsets[plane] = offset;
+ offset += bo->sizes[plane];
+ }
+
+ bo->total_size = offset;
+
+ return 0;
+}
+
static int i915_bo_create_for_modifier(struct bo *bo, uint32_t width, uint32_t height,
uint32_t format, uint64_t modifier)
{
int ret;
size_t plane;
- uint32_t stride;
struct drm_i915_gem_create gem_create;
struct drm_i915_gem_set_tiling gem_set_tiling;
break;
}
- stride = drv_stride_from_format(format, width, 0);
-
- ret = i915_align_dimensions(bo, bo->tiling, &stride, &height);
- if (ret)
- return ret;
+ bo->format_modifiers[0] = modifier;
- /*
- * HAL_PIXEL_FORMAT_YV12 requires the buffer height not be aligned, but we need to keep
- * total size as with aligned height to ensure enough padding space after each plane to
- * satisfy GPU alignment requirements.
- *
- * We do it by first calling drv_bo_from_format() with aligned height and
- * DRM_FORMAT_YVU420, which allows height alignment, saving the total size it calculates
- * and then calling it again with requested parameters.
- *
- * This relies on the fact that i965 driver uses separate surfaces for each plane and
- * contents of padding bytes is not affected, as it is only used to satisfy GPU cache
- * requests.
- *
- * This is enforced by Mesa in src/intel/isl/isl_gen8.c, inside
- * isl_gen8_choose_image_alignment_el(), which is used for GEN9 and GEN8.
- */
if (format == DRM_FORMAT_YVU420_ANDROID) {
- uint32_t unaligned_height = bo->height;
- size_t total_size;
-
- drv_bo_from_format(bo, stride, height, DRM_FORMAT_YVU420);
- total_size = bo->total_size;
- drv_bo_from_format(bo, stride, unaligned_height, format);
- bo->total_size = total_size;
- } else {
+ /*
+ * We only need to be able to use this as a linear texture,
+ * which doesn't put any HW restrictions on how we lay it
+ * out. The Android format does require the stride to be a
+ * multiple of 16 and expects the Cr and Cb stride to be
+ * ALIGN(Y_stride / 2, 16), which we can make happen by
+ * aligning to 32 bytes here.
+ */
+ uint32_t stride = ALIGN(width, 32);
drv_bo_from_format(bo, stride, height, format);
+ } else {
+ i915_bo_from_format(bo, width, height, format);
}
- /*
- * Quoting Mesa ISL library:
- *
- * - For linear surfaces, additional padding of 64 bytes is required at
- * the bottom of the surface. This is in addition to the padding
- * required above.
- */
- if (bo->tiling == I915_TILING_NONE)
- bo->total_size += 64;
-
memset(&gem_create, 0, sizeof(gem_create));
gem_create.size = bo->total_size;
ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create);
if (ret) {
- fprintf(stderr, "drv: DRM_IOCTL_I915_GEM_CREATE failed (size=%llu)\n",
- gem_create.size);
+ drv_log("DRM_IOCTL_I915_GEM_CREATE failed (size=%llu)\n", gem_create.size);
return ret;
}
gem_close.handle = bo->handles[0].u32;
drmIoctl(bo->drv->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
- fprintf(stderr, "drv: DRM_IOCTL_I915_GEM_SET_TILING failed with %d", errno);
+ drv_log("DRM_IOCTL_I915_GEM_SET_TILING failed with %d\n", errno);
return -errno;
}
modifier = drv_pick_modifier(modifiers, count, modifier_order, ARRAY_SIZE(modifier_order));
- bo->format_modifiers[0] = modifier;
-
return i915_bo_create_for_modifier(bo, width, height, format, modifier);
}
ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_GET_TILING, &gem_get_tiling);
if (ret) {
drv_gem_bo_destroy(bo);
- fprintf(stderr, "drv: DRM_IOCTL_I915_GEM_GET_TILING failed.");
+ drv_log("DRM_IOCTL_I915_GEM_GET_TILING failed.\n");
return ret;
}
ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_map);
if (ret) {
- fprintf(stderr, "drv: DRM_IOCTL_I915_GEM_MMAP failed\n");
+ drv_log("DRM_IOCTL_I915_GEM_MMAP failed\n");
return MAP_FAILED;
}
ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &gem_map);
if (ret) {
- fprintf(stderr, "drv: DRM_IOCTL_I915_GEM_MMAP_GTT failed\n");
+ drv_log("DRM_IOCTL_I915_GEM_MMAP_GTT failed\n");
return MAP_FAILED;
}
}
if (addr == MAP_FAILED) {
- fprintf(stderr, "drv: i915 GEM mmap failed\n");
+ drv_log("i915 GEM mmap failed\n");
return addr;
}
ret = drmIoctl(bo->drv->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
if (ret) {
- fprintf(stderr, "drv: DRM_IOCTL_I915_GEM_SET_DOMAIN with %d\n", ret);
+ drv_log("DRM_IOCTL_I915_GEM_SET_DOMAIN with %d\n", ret);
return ret;
}
/*HACK: See b/28671744 */
return DRM_FORMAT_XBGR8888;
case DRM_FORMAT_FLEX_YCbCr_420_888:
- /* KBL camera subsystem requires NV12. */
- if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE))
- return DRM_FORMAT_NV12;
- return DRM_FORMAT_YVU420;
+ /*
+ * KBL camera subsystem requires NV12. Our other use cases
+ * don't care:
+ * - Hardware video supports NV12,
+ * - USB Camera HALv3 supports NV12,
+ * - USB Camera HALv1 doesn't use this format.
+ * Moreover, NV12 is preferred for video, due to overlay
+ * support on SKL+.
+ */
+ return DRM_FORMAT_NV12;
default:
return format;
}