|
|
@ -30,6 +30,7 @@ |
|
|
|
#include <unistd.h> |
|
|
|
#include <unistd.h> |
|
|
|
#include <linux/input.h> |
|
|
|
#include <linux/input.h> |
|
|
|
#include <assert.h> |
|
|
|
#include <assert.h> |
|
|
|
|
|
|
|
#include <sys/mman.h> |
|
|
|
|
|
|
|
|
|
|
|
#include <xf86drm.h> |
|
|
|
#include <xf86drm.h> |
|
|
|
#include <xf86drmMode.h> |
|
|
|
#include <xf86drmMode.h> |
|
|
@ -114,11 +115,17 @@ struct drm_mode { |
|
|
|
struct drm_output; |
|
|
|
struct drm_output; |
|
|
|
|
|
|
|
|
|
|
|
struct drm_fb { |
|
|
|
struct drm_fb { |
|
|
|
struct gbm_bo *bo; |
|
|
|
|
|
|
|
struct drm_output *output; |
|
|
|
struct drm_output *output; |
|
|
|
uint32_t fb_id; |
|
|
|
uint32_t fb_id, stride, handle, size; |
|
|
|
|
|
|
|
int fd; |
|
|
|
int is_client_buffer; |
|
|
|
int is_client_buffer; |
|
|
|
struct weston_buffer_reference buffer_ref; |
|
|
|
struct weston_buffer_reference buffer_ref; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Used by gbm fbs */ |
|
|
|
|
|
|
|
struct gbm_bo *bo; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Used by dumb fbs */ |
|
|
|
|
|
|
|
void *map; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct drm_output { |
|
|
|
struct drm_output { |
|
|
@ -212,28 +219,109 @@ drm_fb_destroy_callback(struct gbm_bo *bo, void *data) |
|
|
|
free(data); |
|
|
|
free(data); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct drm_fb * |
|
|
|
|
|
|
|
drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct drm_fb *fb; |
|
|
|
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct drm_mode_create_dumb create_arg; |
|
|
|
|
|
|
|
struct drm_mode_destroy_dumb destroy_arg; |
|
|
|
|
|
|
|
struct drm_mode_map_dumb map_arg; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fb = calloc(1, sizeof *fb); |
|
|
|
|
|
|
|
if (!fb) |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
create_arg.bpp = 32; |
|
|
|
|
|
|
|
create_arg.width = width; |
|
|
|
|
|
|
|
create_arg.height = height; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); |
|
|
|
|
|
|
|
if (ret) |
|
|
|
|
|
|
|
goto err_fb; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fb->handle = create_arg.handle; |
|
|
|
|
|
|
|
fb->stride = create_arg.pitch; |
|
|
|
|
|
|
|
fb->size = create_arg.size; |
|
|
|
|
|
|
|
fb->fd = ec->drm.fd; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32, |
|
|
|
|
|
|
|
fb->stride, fb->handle, &fb->fb_id); |
|
|
|
|
|
|
|
if (ret) |
|
|
|
|
|
|
|
goto err_bo; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memset(&map_arg, 0, sizeof(map_arg)); |
|
|
|
|
|
|
|
map_arg.handle = fb->handle; |
|
|
|
|
|
|
|
drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ret) |
|
|
|
|
|
|
|
goto err_add_fb; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fb->map = mmap(0, fb->size, PROT_WRITE, |
|
|
|
|
|
|
|
MAP_SHARED, ec->drm.fd, map_arg.offset); |
|
|
|
|
|
|
|
if (fb->map == MAP_FAILED) |
|
|
|
|
|
|
|
goto err_add_fb; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return fb; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err_add_fb: |
|
|
|
|
|
|
|
drmModeRmFB(ec->drm.fd, fb->fb_id); |
|
|
|
|
|
|
|
err_bo: |
|
|
|
|
|
|
|
memset(&destroy_arg, 0, sizeof(destroy_arg)); |
|
|
|
|
|
|
|
destroy_arg.handle = create_arg.handle; |
|
|
|
|
|
|
|
drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); |
|
|
|
|
|
|
|
err_fb: |
|
|
|
|
|
|
|
free(fb); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
|
|
|
drm_fb_destroy_dumb(struct drm_fb *fb) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct drm_mode_destroy_dumb destroy_arg; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!fb->map) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (fb->fb_id) |
|
|
|
|
|
|
|
drmModeRmFB(fb->fd, fb->fb_id); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
weston_buffer_reference(&fb->buffer_ref, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
munmap(fb->map, fb->size); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
memset(&destroy_arg, 0, sizeof(destroy_arg)); |
|
|
|
|
|
|
|
destroy_arg.handle = fb->handle; |
|
|
|
|
|
|
|
drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(fb); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct drm_fb * |
|
|
|
static struct drm_fb * |
|
|
|
drm_fb_get_from_bo(struct gbm_bo *bo, |
|
|
|
drm_fb_get_from_bo(struct gbm_bo *bo, |
|
|
|
struct drm_compositor *compositor, uint32_t format) |
|
|
|
struct drm_compositor *compositor, uint32_t format) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct drm_fb *fb = gbm_bo_get_user_data(bo); |
|
|
|
struct drm_fb *fb = gbm_bo_get_user_data(bo); |
|
|
|
uint32_t width, height, stride, handle; |
|
|
|
uint32_t width, height; |
|
|
|
uint32_t handles[4], pitches[4], offsets[4]; |
|
|
|
uint32_t handles[4], pitches[4], offsets[4]; |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
if (fb) |
|
|
|
if (fb) |
|
|
|
return fb; |
|
|
|
return fb; |
|
|
|
|
|
|
|
|
|
|
|
fb = malloc(sizeof *fb); |
|
|
|
fb = calloc(1, sizeof *fb); |
|
|
|
|
|
|
|
if (!fb) |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
|
|
fb->bo = bo; |
|
|
|
fb->bo = bo; |
|
|
|
fb->is_client_buffer = 0; |
|
|
|
|
|
|
|
fb->buffer_ref.buffer = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
width = gbm_bo_get_width(bo); |
|
|
|
width = gbm_bo_get_width(bo); |
|
|
|
height = gbm_bo_get_height(bo); |
|
|
|
height = gbm_bo_get_height(bo); |
|
|
|
stride = gbm_bo_get_stride(bo); |
|
|
|
fb->stride = gbm_bo_get_stride(bo); |
|
|
|
handle = gbm_bo_get_handle(bo).u32; |
|
|
|
fb->handle = gbm_bo_get_handle(bo).u32; |
|
|
|
|
|
|
|
fb->size = fb->stride * height; |
|
|
|
|
|
|
|
fb->fd = compositor->drm.fd; |
|
|
|
|
|
|
|
|
|
|
|
if (compositor->min_width > width || width > compositor->max_width || |
|
|
|
if (compositor->min_width > width || width > compositor->max_width || |
|
|
|
compositor->min_height > height || |
|
|
|
compositor->min_height > height || |
|
|
@ -245,8 +333,8 @@ drm_fb_get_from_bo(struct gbm_bo *bo, |
|
|
|
ret = -1; |
|
|
|
ret = -1; |
|
|
|
|
|
|
|
|
|
|
|
if (format && !compositor->no_addfb2) { |
|
|
|
if (format && !compositor->no_addfb2) { |
|
|
|
handles[0] = handle; |
|
|
|
handles[0] = fb->handle; |
|
|
|
pitches[0] = stride; |
|
|
|
pitches[0] = fb->stride; |
|
|
|
offsets[0] = 0; |
|
|
|
offsets[0] = 0; |
|
|
|
|
|
|
|
|
|
|
|
ret = drmModeAddFB2(compositor->drm.fd, width, height, |
|
|
|
ret = drmModeAddFB2(compositor->drm.fd, width, height, |
|
|
@ -261,7 +349,7 @@ drm_fb_get_from_bo(struct gbm_bo *bo, |
|
|
|
|
|
|
|
|
|
|
|
if (ret) |
|
|
|
if (ret) |
|
|
|
ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32, |
|
|
|
ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32, |
|
|
|
stride, handle, &fb->fb_id); |
|
|
|
fb->stride, fb->handle, &fb->fb_id); |
|
|
|
|
|
|
|
|
|
|
|
if (ret) { |
|
|
|
if (ret) { |
|
|
|
weston_log("failed to create kms fb: %m\n"); |
|
|
|
weston_log("failed to create kms fb: %m\n"); |
|
|
@ -293,7 +381,9 @@ drm_output_release_fb(struct drm_output *output, struct drm_fb *fb) |
|
|
|
if (!fb) |
|
|
|
if (!fb) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
if (fb->bo) { |
|
|
|
if (fb->map) { |
|
|
|
|
|
|
|
drm_fb_destroy_dumb(fb); |
|
|
|
|
|
|
|
} else if (fb->bo) { |
|
|
|
if (fb->is_client_buffer) |
|
|
|
if (fb->is_client_buffer) |
|
|
|
gbm_bo_destroy(fb->bo); |
|
|
|
gbm_bo_destroy(fb->bo); |
|
|
|
else |
|
|
|
else |
|
|
@ -1035,6 +1125,7 @@ init_drm(struct drm_compositor *ec, struct udev_device *device) |
|
|
|
|
|
|
|
|
|
|
|
ec->drm.fd = fd; |
|
|
|
ec->drm.fd = fd; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|