}
}
+static int amdgpu_bo_get_plane_fd(struct bo *bo, size_t plane)
+{
+ if (bo->priv)
+ dri_bo_get_plane_fd(bo, plane);
+ else
+ /* Fallback to default implementation */
+ return -1;
+}
+
static int amdgpu_bo_invalidate(struct bo *bo, struct mapping *mapping)
{
int ret;
.bo_import = amdgpu_import_bo,
.bo_map = amdgpu_map_bo,
.bo_unmap = amdgpu_unmap_bo,
+ .bo_get_plane_fd = amdgpu_bo_get_plane_fd,
.bo_invalidate = amdgpu_bo_invalidate,
.resolve_format = amdgpu_resolve_format,
.num_planes_from_modifier = dri_num_planes_from_modifier,
#include <sys/mman.h>
#include <syscall.h>
#include <xf86drm.h>
+#include <xf86drmMode.h>
#include "../drv_priv.h"
#include "../helpers.h"
}
}
-static struct driver *init_try_node(int idx, char const *str)
+static bool is_kms_dev(const char *path)
+{
+ int fd = open(path, O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ return false;
+
+ auto res = drmModeGetResources(fd);
+ if (!res) {
+ close(fd);
+ return false;
+ }
+
+ bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 && res->count_encoders > 0;
+
+ drmModeFreeResources(res);
+ close(fd);
+
+ return is_kms;
+}
+
+static struct driver *init_try_node(int idx, bool use_card_node, bool try_generic)
{
int fd;
char *node;
struct driver *drv;
- if (asprintf(&node, str, DRM_DIR_NAME, idx) < 0)
+ if (asprintf(&node, use_card_node ? "%s/card%d" : "%s/renderD%d", DRM_DIR_NAME, idx) < 0)
return NULL;
+ if (use_card_node && !is_kms_dev(node)) {
+ free(node);
+ return NULL;
+ }
+
fd = open(node, O_RDWR, 0);
free(node);
if (fd < 0)
return NULL;
- drv = drv_create(fd);
+ drv = drv_create(fd, try_generic);
if (!drv)
close(fd);
* TODO(gsingh): Enable render nodes on udl/evdi.
*/
- char const *render_nodes_fmt = "%s/renderD%d";
- char const *card_nodes_fmt = "%s/card%d";
uint32_t num_nodes = DRM_NUM_NODES;
uint32_t min_render_node = DRM_RENDER_NODE_START;
uint32_t max_render_node = (min_render_node + num_nodes);
// Try render nodes...
for (uint32_t i = min_render_node; i < max_render_node; i++) {
- drv_ = init_try_node(i, render_nodes_fmt);
+ drv_ = init_try_node(i, false, false);
if (drv_)
return 0;
}
// Try card nodes... for vkms mostly.
for (uint32_t i = min_card_node; i < max_card_node; i++) {
- drv_ = init_try_node(i, card_nodes_fmt);
+ drv_ = init_try_node(i, true, false);
if (drv_)
return 0;
}
+#ifdef DRI_GENERIC_DRV
+ // Try card nodes using mesa3d/dri backend
+ for (uint32_t i = min_card_node; i < max_card_node; i++) {
+ drv_ = init_try_node(i, true, true);
+ if (drv_)
+ return 0;
+ }
+
+ // Try render nodes using mesa3d/dri backend
+ for (uint32_t i = min_render_node; i < max_render_node; i++) {
+ drv_ = init_try_node(i, false, true);
+ if (drv_)
+ return 0;
+ }
+#endif
+
return -ENODEV;
}
name = (char *)(&hnd->base.data[hnd->name_offset]);
snprintf(name, descriptor->name.size() + 1, "%s", descriptor->name.c_str());
- id = drv_bo_get_plane_handle(bo, 0).u32;
+ id = hnd->id;
auto buffer = new cros_gralloc_buffer(id, bo, hnd, hnd->fds[hnd->num_planes],
hnd->reserved_region_size);
return 0;
}
- if (drmPrimeFDToHandle(drv_get_fd(drv_), hnd->fds[0], &id)) {
- drv_log("drmPrimeFDToHandle failed.\n");
- return -errno;
- }
+ id = hnd->id;
if (buffers_.count(id)) {
buffer = buffers_[id];
if (!bo)
return -EFAULT;
- id = drv_bo_get_plane_handle(bo, 0).u32;
-
buffer = new cros_gralloc_buffer(id, bo, nullptr, hnd->fds[hnd->num_planes],
hnd->reserved_region_size);
buffers_.emplace(id, buffer);
* found in the LICENSE file.
*/
-#ifdef DRV_AMDGPU
+#if defined(DRI_GENERIC_DRV) || defined(DRV_AMDGPU)
#include <assert.h>
#include <dlfcn.h>
#include "helpers.h"
#include "util.h"
+#ifdef DRI_GENERIC_DRV
+#include <loader.h>
+#endif
+
static const struct {
uint32_t drm_format;
int dri_image_format;
return false;
}
-/*
- * Close Gem Handle
- */
-static void close_gem_handle(uint32_t handle, int fd)
+int dri_bo_get_plane_fd(struct bo *bo, size_t plane)
{
- struct drm_gem_close gem_close = { 0 };
- int ret = 0;
+ struct dri_driver *dri = bo->drv->priv;
+ __DRIimage *plane_image = NULL;
+ int fd = -1;
- gem_close.handle = handle;
- ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
- if (ret)
- drv_log("DRM_IOCTL_GEM_CLOSE failed (handle=%x) error %d\n", handle, ret);
-}
+ plane_image = dri->image_extension->fromPlanar(bo->priv, plane, NULL);
+ __DRIimage *image = plane_image ? plane_image : bo->priv;
+
+ dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
+
+ if (plane_image)
+ dri->image_extension->destroyImage(plane_image);
+ return fd;
+}
/*
* The DRI GEM namespace may be different from the minigbm's driver GEM namespace. We have
* to import into minigbm.
*/
static int import_into_minigbm(struct dri_driver *dri, struct bo *bo)
{
- uint32_t handle;
int ret, modifier_upper, modifier_lower, num_planes, i, j;
off_t dmabuf_sizes[DRV_MAX_PLANES];
__DRIimage *plane_image = NULL;
return -errno;
}
- bo->meta.num_planes = num_planes;
-
for (i = 0; i < num_planes; ++i) {
int prime_fd, stride, offset;
plane_image = dri->image_extension->fromPlanar(bo->priv, i, NULL);
lseek(prime_fd, 0, SEEK_SET);
- ret = drmPrimeFDToHandle(bo->drv->fd, prime_fd, &handle);
-
close(prime_fd);
- if (ret) {
- drv_log("drmPrimeFDToHandle failed with %s\n", strerror(errno));
+ if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE,
+ &bo->handles[i].s32)) {
+ drv_log("queryImage() failed with %s\n", strerror(errno));
+ ret = -errno;
goto cleanup;
}
- bo->handles[i].u32 = handle;
-
bo->meta.strides[i] = stride;
bo->meta.offsets[i] = offset;
/* Multiple equivalent handles) */
if (i == j)
break;
-
- /* This kind of goes horribly wrong when we already imported
- * the same handles earlier, as we should really reference
- * count handles. */
- close_gem_handle(bo->handles[i].u32, bo->drv->fd);
}
return ret;
}
struct dri_driver *dri = drv->priv;
- dri->fd = open(drmGetRenderDeviceNameFromFd(drv_get_fd(drv)), O_RDWR);
+ dri->fd = open(drmGetDeviceNameFromFd(drv_get_fd(drv)), O_RDWR);
if (dri->fd < 0)
return -ENODEV;
close(dri->fd);
return -ENODEV;
}
+/*
+ * The caller is responsible for setting drv->priv to a structure that derives from dri_driver.
+ */
+int dri_init2(struct driver *drv)
+{
+#ifdef DRI_GENERIC_DRV
+ char dri_pathname[64];
+ char drv_suffix[32];
+
+ char *drv_name = loader_get_driver_for_fd(drv->fd);
+
+ sprintf(dri_pathname, STRINGIZE(DRI_DRIVER_DIR) "/%s_dri.so", drv_name);
+
+ strcpy(drv_suffix, drv_name);
+ free(drv_name);
+
+ /* replace all '-' chars with '_' in drv_suffix to use in dlsym() */
+ char *current_pos = strchr(drv_suffix, '-');
+ while (current_pos) {
+ *current_pos = '_';
+ current_pos = strchr(current_pos, '-');
+ }
+
+ if (dri_init(drv, dri_pathname, drv_suffix)) {
+ drv_log("dri_init failed for (%s) , (%s)", dri_pathname, drv_suffix);
+ return -ENODEV;
+ }
+
+ return 0;
+#else
+ return -ENOTSUPP;
+#endif
+}
/*
* The caller is responsible for freeing drv->priv.
close(dri->fd);
}
-int dri_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
- uint64_t use_flags)
+int dri_bo_create_common(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
+ uint64_t use_flags, const uint64_t *modifiers, uint32_t modifier_count)
{
+ uint32_t width_ = width;
+ uint32_t height_ = height;
unsigned int dri_use;
int ret, dri_format;
+ int dri_format_unavailable = false;
struct dri_driver *dri = bo->drv->priv;
dri_format = drm_format_to_dri_format(format);
+ /* Video buffers can't be allocated using DRI */
+ if (!dri_format)
+ dri_format_unavailable = true;
/* Gallium drivers require shared to get the handle and stride. */
dri_use = __DRI_IMAGE_USE_SHARE;
dri_use |= __DRI_IMAGE_USE_SCANOUT;
if (use_flags & BO_USE_CURSOR)
dri_use |= __DRI_IMAGE_USE_CURSOR;
- if (use_flags & BO_USE_LINEAR)
+ if (use_flags & (BO_USE_LINEAR | BO_USE_SW_MASK))
dri_use |= __DRI_IMAGE_USE_LINEAR;
- bo->priv = dri->image_extension->createImage(dri->device, width, height, dri_format,
- dri_use, NULL);
+ if (dri_format_unavailable) {
+ int stride = drv_stride_from_format(format, width, 0);
+ drv_bo_from_format(bo, stride, height, format);
+ dri_format = __DRI_IMAGE_FORMAT_R8;
+ dri_use |= __DRI_IMAGE_USE_LINEAR;
+ width_ = stride / drv_bytes_per_pixel_from_format(format, 0);
+ height_ = DIV_ROUND_UP(bo->meta.total_size, width_);
+ }
+
+ if (modifier_count == 0) {
+ bo->priv = dri->image_extension->createImage(dri->device, width_, height_,
+ dri_format, dri_use, NULL);
+ } else {
+ if (!dri->image_extension->createImageWithModifiers) {
+ return -ENOENT;
+ }
+ bo->priv = dri->image_extension->createImageWithModifiers(
+ dri->device, width, height, dri_format, modifiers, modifier_count, NULL);
+ }
+
if (!bo->priv) {
ret = -errno;
return ret;
}
- ret = import_into_minigbm(dri, bo);
- if (ret)
- goto free_image;
-
- return 0;
+ if (dri_format_unavailable) {
+ __DRIimage *plane_image = dri->image_extension->fromPlanar(bo->priv, 0, NULL);
+ __DRIimage *image = plane_image ? plane_image : bo->priv;
-free_image:
- dri->image_extension->destroyImage(bo->priv);
- return ret;
-}
+ if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE,
+ &bo->handles[0].s32)) {
+ drv_log("queryImage() failed with error %s\n", strerror(errno));
+ ret = -errno;
+ goto free_image;
+ }
-int dri_bo_create_with_modifiers(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
- const uint64_t *modifiers, uint32_t modifier_count)
-{
- int ret, dri_format;
- struct dri_driver *dri = bo->drv->priv;
+ if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE,
+ (int32_t *)&bo->meta.strides[0])) {
+ drv_log("queryImage() failed with error %s\n", strerror(errno));
+ ret = -errno;
+ goto free_image;
+ }
- if (!dri->image_extension->createImageWithModifiers) {
- return -ENOENT;
- }
+ drv_bo_from_format(bo, bo->meta.strides[0], height, format);
- dri_format = drm_format_to_dri_format(format);
+ if (plane_image)
+ dri->image_extension->destroyImage(plane_image);
- bo->priv = dri->image_extension->createImageWithModifiers(
- dri->device, width, height, dri_format, modifiers, modifier_count, NULL);
- if (!bo->priv) {
- ret = -errno;
- return ret;
+ for (size_t plane = 1; plane < bo->meta.num_planes; plane++)
+ bo->handles[plane].u32 = bo->handles[0].u32;
+ } else {
+ ret = import_into_minigbm(dri, bo);
+ if (ret)
+ goto free_image;
}
- ret = import_into_minigbm(dri, bo);
- if (ret)
- goto free_image;
-
return 0;
free_image:
return ret;
}
+int dri_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
+ uint64_t use_flags)
+{
+ return dri_bo_create_common(bo, width, height, format, use_flags, NULL, 0);
+}
+
+int dri_bo_create_with_modifiers(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
+ const uint64_t *modifiers, uint32_t modifier_count)
+{
+ return dri_bo_create_common(bo, width, height, format, 0, modifiers, modifier_count);
+}
+
int dri_bo_import(struct bo *bo, struct drv_import_fd_data *data)
{
int ret;
struct dri_driver *dri = bo->drv->priv;
assert(bo->priv);
- close_gem_handle(bo->handles[0].u32, bo->drv->fd);
dri->image_extension->destroyImage(bo->priv);
bo->priv = NULL;
return 0;
* found in the LICENSE file.
*/
-#ifdef DRV_AMDGPU
+#if defined(DRI_GENERIC_DRV) || defined(DRV_AMDGPU)
+#ifndef __DRIH__
+#define __DRIH__
+
+#define HAVE_LIBDRM
// Avoid transitively including a bunch of unnecessary headers.
#define GL_GLEXT_LEGACY
#include "GL/internal/dri_interface.h"
};
int dri_init(struct driver *drv, const char *dri_so_path, const char *driver_suffix);
+int dri_init2(struct driver *drv);
void dri_close(struct driver *drv);
int dri_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
uint64_t use_flags);
int dri_bo_destroy(struct bo *bo);
void *dri_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags);
int dri_bo_unmap(struct bo *bo, struct vma *vma);
+int dri_bo_get_plane_fd(struct bo *bo, size_t plane);
+
size_t dri_num_planes_from_modifier(struct driver *drv, uint32_t format, uint64_t modifier);
#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifdef DRI_GENERIC_DRV
+
+#include <string.h>
+#include <xf86drm.h>
+
+#include "dri.h"
+#include "drv_priv.h"
+#include "helpers.h"
+#include "util.h"
+#include <errno.h>
+
+static const uint32_t scanout_render_formats[] = { DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGB565 };
+
+static const uint32_t texture_only_formats[] = { DRM_FORMAT_NV12, DRM_FORMAT_NV21,
+ DRM_FORMAT_YVU420, DRM_FORMAT_YVU420_ANDROID };
+
+static int dri_generic_init(struct driver *drv)
+{
+ struct dri_driver *dri;
+
+ dri = calloc(1, sizeof(struct dri_driver));
+ if (!dri)
+ return -ENOMEM;
+
+ drv->priv = dri;
+
+ if (dri_init2(drv)) {
+ free(dri);
+ drv->priv = NULL;
+ return -ENODEV;
+ }
+
+ drv_add_combinations(drv, scanout_render_formats, ARRAY_SIZE(scanout_render_formats),
+ &LINEAR_METADATA, BO_USE_RENDER_MASK | BO_USE_SCANOUT);
+
+ drv_add_combinations(drv, texture_only_formats, ARRAY_SIZE(texture_only_formats),
+ &LINEAR_METADATA, BO_USE_TEXTURE_MASK);
+
+ drv_modify_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA,
+ BO_USE_HW_VIDEO_ENCODER | BO_USE_HW_VIDEO_DECODER |
+ BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
+ drv_modify_combination(drv, DRM_FORMAT_NV21, &LINEAR_METADATA, BO_USE_HW_VIDEO_ENCODER);
+
+ return drv_modify_linear_combinations(drv);
+}
+
+static uint32_t dri_generic_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags)
+{
+ switch (format) {
+ case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
+ /* Camera subsystem requires NV12. */
+ if (use_flags & (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE))
+ return DRM_FORMAT_NV12;
+ /*HACK: See b/28671744 */
+ return DRM_FORMAT_XBGR8888;
+ case DRM_FORMAT_FLEX_YCbCr_420_888:
+ return DRM_FORMAT_NV12;
+ case DRM_FORMAT_BGR565:
+ /* mesa3d doesn't support BGR565 */
+ return DRM_FORMAT_RGB565;
+ default:
+ return format;
+ }
+}
+
+const struct backend backend_dri_generic = {
+ .name = "dri_generic",
+ .init = dri_generic_init,
+ .close = dri_close,
+ .bo_create = dri_bo_create,
+ .bo_create_with_modifiers = dri_bo_create_with_modifiers,
+ .bo_destroy = dri_bo_destroy,
+ .bo_import = dri_bo_import,
+ .bo_map = dri_bo_map,
+ .bo_unmap = dri_bo_unmap,
+ .bo_get_plane_fd = dri_bo_get_plane_fd,
+ .resolve_format = dri_generic_resolve_format,
+ .num_planes_from_modifier = dri_num_planes_from_modifier,
+};
+
+#endif
extern const struct backend backend_vc4;
#endif
+#ifndef DRI_GENERIC_DRV
// Dumb / generic drivers
extern const struct backend backend_evdi;
extern const struct backend backend_marvell;
extern const struct backend backend_virtio_gpu;
extern const struct backend backend_udl;
extern const struct backend backend_vkms;
+#endif
+
+#ifdef DRI_GENERIC_DRV
+extern const struct backend backend_dri_generic;
+#endif
static const struct backend *drv_get_backend(int fd)
{
#ifdef DRV_VC4
&backend_vc4,
#endif
+#ifndef DRI_GENERIC_DRV
&backend_evdi, &backend_marvell, &backend_meson, &backend_nouveau,
&backend_komeda, &backend_radeon, &backend_synaptics, &backend_virtio_gpu,
&backend_udl, &backend_virtio_gpu, &backend_vkms
+#endif
};
for (i = 0; i < ARRAY_SIZE(backend_list); i++) {
return NULL;
}
-struct driver *drv_create(int fd)
+struct driver *drv_create(int fd, bool try_generic)
{
struct driver *drv;
int ret;
drv->fd = fd;
drv->backend = drv_get_backend(fd);
+#ifdef DRI_GENERIC_DRV
+ if (!drv->backend && try_generic)
+ drv->backend = &backend_dri_generic;
+#endif
+
if (!drv->backend)
goto free_driver;
return -EINVAL;
}
+ if (bo->drv->backend->bo_get_plane_fd) {
+ fd = bo->drv->backend->bo_get_plane_fd(bo, plane);
+
+ if (fd >= 0)
+ return fd;
+ }
+
ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32, DRM_CLOEXEC | DRM_RDWR, &fd);
// Older DRM implementations blocked DRM_RDWR, but gave a read/write mapping anyways
uint32_t refcount;
};
-struct driver *drv_create(int fd);
+struct driver *drv_create(int fd, bool try_generic);
void drv_destroy(struct driver *drv);
int (*bo_compute_metadata)(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
uint64_t use_flags, const uint64_t *modifiers, uint32_t count);
int (*bo_create_from_metadata)(struct bo *bo);
+ int (*bo_get_plane_fd)(struct bo *bo, size_t plane);
int (*bo_destroy)(struct bo *bo);
int (*bo_import)(struct bo *bo, struct drv_import_fd_data *data);
void *(*bo_map)(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags);
* found in the LICENSE file.
*/
+#ifndef DRI_GENERIC_DRV
+
#include "drv_priv.h"
#include "helpers.h"
#include "util.h"
INIT_DUMB_DRIVER(synaptics)
INIT_DUMB_DRIVER(udl)
INIT_DUMB_DRIVER(vkms)
+
+#endif