blob: 755a740797b798dcdbc5d26966e35e99698f728f [file] [log] [blame]
/*
* Copyright 2016 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.
*/
#include "bs_drm.h"
#define MAX_PLANE_COUNT 4
struct bs_drm_fb_builder {
int fd;
uint32_t width;
uint32_t height;
uint32_t format;
size_t plane_count;
uint32_t handles[MAX_PLANE_COUNT];
uint32_t strides[MAX_PLANE_COUNT];
uint32_t offsets[MAX_PLANE_COUNT];
uint64_t modifier;
};
void bs_drm_fb_builder_init(struct bs_drm_fb_builder *self)
{
assert(self);
self->fd = -1;
self->modifier = DRM_FORMAT_MOD_INVALID;
}
struct bs_drm_fb_builder *bs_drm_fb_builder_new()
{
struct bs_drm_fb_builder *self = calloc(1, sizeof(struct bs_drm_fb_builder));
assert(self);
bs_drm_fb_builder_init(self);
return self;
}
void bs_drm_fb_builder_destroy(struct bs_drm_fb_builder **self)
{
assert(self);
assert(*self);
free(*self);
*self = NULL;
}
void bs_drm_fb_builder_gbm_bo(struct bs_drm_fb_builder *self, struct gbm_bo *bo)
{
assert(self);
assert(bo);
struct gbm_device *gbm = gbm_bo_get_device(bo);
assert(gbm);
self->fd = gbm_device_get_fd(gbm);
self->width = gbm_bo_get_width(bo);
self->height = gbm_bo_get_height(bo);
self->format = gbm_bo_get_format(bo);
self->plane_count = gbm_bo_get_plane_count(bo);
self->modifier = gbm_bo_get_modifier(bo);
if (self->plane_count > MAX_PLANE_COUNT) {
bs_debug_print("WARNING", __func__, __FILE__, __LINE__,
"only using first %d planes out of buffer object's %zu planes",
MAX_PLANE_COUNT, self->plane_count);
self->plane_count = MAX_PLANE_COUNT;
}
for (size_t plane_index = 0; plane_index < self->plane_count; plane_index++) {
self->handles[plane_index] = gbm_bo_get_handle_for_plane(bo, plane_index).u32;
self->strides[plane_index] = gbm_bo_get_stride_for_plane(bo, plane_index);
self->offsets[plane_index] = gbm_bo_get_offset(bo, plane_index);
}
}
void bs_drm_fb_builder_format(struct bs_drm_fb_builder *self, uint32_t format)
{
assert(self);
self->format = format;
}
uint32_t bs_drm_fb_builder_create_fb(struct bs_drm_fb_builder *self)
{
assert(self);
if (self->fd < 0) {
bs_debug_error("failed to create drm fb: card fd %d is invalid", self->fd);
return 0;
}
if (self->width <= 0 || self->height <= 0) {
bs_debug_error("failed to create drm fb: dimensions %ux%u are invalid", self->width,
self->height);
return 0;
}
if (self->format == 0) {
bs_debug_error("failed to create drm fb: 0 format is invalid");
return 0;
}
// Intel cannot scanout AR30/AB30 formats, but can do the X variants.
unsigned format = self->format;
if (format == GBM_FORMAT_ARGB2101010)
format = GBM_FORMAT_XRGB2101010;
if (format == GBM_FORMAT_ABGR2101010)
format = GBM_FORMAT_XBGR2101010;
if (self->plane_count == 0 || self->plane_count > MAX_PLANE_COUNT) {
bs_debug_error("failed to create drm fb: plane count %zu is invalid\n",
self->plane_count);
return 0;
}
for (size_t plane_index = self->plane_count; plane_index < MAX_PLANE_COUNT; plane_index++) {
self->handles[plane_index] = 0;
self->strides[plane_index] = 0;
self->offsets[plane_index] = 0;
}
uint32_t fb_id;
int ret = 0;
if (self->modifier != DRM_FORMAT_MOD_INVALID &&
bs_are_modifier_supported(self->fd, DRM_PLANE_TYPE_PRIMARY)) {
uint64_t modifiers[4] = { DRM_FORMAT_MOD_NONE, DRM_FORMAT_MOD_NONE,
DRM_FORMAT_MOD_NONE, DRM_FORMAT_MOD_NONE };
for (int i = 0; i < self->plane_count; i++)
modifiers[i] = self->modifier;
ret = drmModeAddFB2WithModifiers(self->fd, self->width, self->height, format,
self->handles, self->strides, self->offsets,
modifiers, &fb_id, DRM_MODE_FB_MODIFIERS);
} else {
ret = drmModeAddFB2(self->fd, self->width, self->height, format,
self->handles, self->strides, self->offsets, &fb_id, 0);
}
if (ret) {
bs_debug_error("failed to create drm fb: %s returned %d",
self->modifier ? "drmModeAddFB2WithModifiers" : "drmModeAddFB2",
ret);
return 0;
}
return fb_id;
}
uint32_t bs_drm_fb_create_gbm(struct gbm_bo *bo)
{
assert(bo);
struct bs_drm_fb_builder builder;
bs_drm_fb_builder_init(&builder);
bs_drm_fb_builder_gbm_bo(&builder, bo);
uint32_t fb_id = bs_drm_fb_builder_create_fb(&builder);
if (!fb_id) {
bs_debug_error("failed to create framebuffer from buffer object");
return 0;
}
return fb_id;
}