diff options
Diffstat (limited to 'video/out/drm_prime.c')
-rw-r--r-- | video/out/drm_prime.c | 101 |
1 files changed, 88 insertions, 13 deletions
diff --git a/video/out/drm_prime.c b/video/out/drm_prime.c index 253fbb6c40..9335fa8e02 100644 --- a/video/out/drm_prime.c +++ b/video/out/drm_prime.c @@ -15,30 +15,41 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> #include <unistd.h> #include <xf86drm.h> #include <xf86drmMode.h> +#include <drm_mode.h> +#include "common/common.h" #include "common/msg.h" #include "drm_common.h" #include "drm_prime.h" -int drm_prime_create_framebuffer(struct mp_log *log, int fd, AVDRMFrameDescriptor *descriptor, int width, int height, - struct drm_prime_framebuffer *framebuffer) +int drm_prime_create_framebuffer(struct mp_log *log, int fd, + AVDRMFrameDescriptor *descriptor, int width, + int height, struct drm_prime_framebuffer *framebuffer, + struct drm_prime_handle_refs *handle_refs) { AVDRMLayerDescriptor *layer = NULL; - uint32_t pitches[4], offsets[4], handles[4]; + uint32_t pitches[4] = { 0 }; + uint32_t offsets[4] = { 0 }; + uint32_t handles[4] = { 0 }; + uint64_t modifiers[4] = { 0 }; int ret, layer_fd; if (descriptor && descriptor->nb_layers) { *framebuffer = (struct drm_prime_framebuffer){0}; for (int object = 0; object < descriptor->nb_objects; object++) { - ret = drmPrimeFDToHandle(fd, descriptor->objects[object].fd, &framebuffer->gem_handles[object]); + ret = drmPrimeFDToHandle(fd, descriptor->objects[object].fd, + &framebuffer->gem_handles[object]); if (ret < 0) { - mp_err(log, "Failed to retrieve the Prime Handle from handle %d (%d).\n", object, descriptor->objects[object].fd); + mp_err(log, "Failed to retrieve the Prime Handle from handle %d (%d).\n", + object, descriptor->objects[object].fd); goto fail; } + modifiers[object] = descriptor->objects[object].format_modifier; } layer = &descriptor->layers[0]; @@ -53,16 +64,29 @@ int drm_prime_create_framebuffer(struct mp_log *log, int fd, AVDRMFrameDescripto pitches[plane] = 0; offsets[plane] = 0; handles[plane] = 0; + modifiers[plane] = 0; } } - ret = drmModeAddFB2(fd, width, height, layer->format, - handles, pitches, offsets, &framebuffer->fb_id, 0); + ret = drmModeAddFB2WithModifiers(fd, width, height, layer->format, + handles, pitches, offsets, + modifiers, &framebuffer->fb_id, + DRM_MODE_FB_MODIFIERS); if (ret < 0) { - mp_err(log, "Failed to create framebuffer on layer %d.\n", 0); - goto fail; + ret = drmModeAddFB2(fd, width, height, layer->format, + handles, pitches, offsets, + &framebuffer->fb_id, 0); + if (ret < 0) { + mp_err(log, "Failed to create framebuffer with drmModeAddFB2 on layer %d: %s\n", + 0, mp_strerror(errno)); + goto fail; + } } - } + + for (int plane = 0; plane < AV_DRM_MAX_PLANES; plane++) { + drm_prime_add_handle_ref(handle_refs, framebuffer->gem_handles[plane]); + } + } return 0; @@ -71,15 +95,66 @@ fail: return -1; } -void drm_prime_destroy_framebuffer(struct mp_log *log, int fd, struct drm_prime_framebuffer *framebuffer) +void drm_prime_destroy_framebuffer(struct mp_log *log, int fd, + struct drm_prime_framebuffer *framebuffer, + struct drm_prime_handle_refs *handle_refs) { if (framebuffer->fb_id) drmModeRmFB(fd, framebuffer->fb_id); for (int i = 0; i < AV_DRM_MAX_PLANES; i++) { - if (framebuffer->gem_handles[i]) - drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &framebuffer->gem_handles[i]); + if (framebuffer->gem_handles[i]) { + drm_prime_remove_handle_ref(handle_refs, + framebuffer->gem_handles[i]); + if (!drm_prime_get_handle_ref_count(handle_refs, + framebuffer->gem_handles[i])) { + drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &framebuffer->gem_handles[i]); + } + } } memset(framebuffer, 0, sizeof(*framebuffer)); } + +void drm_prime_init_handle_ref_count(void *talloc_parent, + struct drm_prime_handle_refs *handle_refs) +{ + handle_refs->handle_ref_count = talloc_zero(talloc_parent, uint32_t); + handle_refs->size = 1; + handle_refs->ctx = talloc_parent; +} + +void drm_prime_add_handle_ref(struct drm_prime_handle_refs *handle_refs, + uint32_t handle) +{ + if (handle) { + if (handle > handle_refs->size) { + handle_refs->size = handle; + MP_TARRAY_GROW(handle_refs->ctx, handle_refs->handle_ref_count, + handle_refs->size); + } + handle_refs->handle_ref_count[handle - 1]++; + } +} + +void drm_prime_remove_handle_ref(struct drm_prime_handle_refs *handle_refs, + uint32_t handle) +{ + if (handle) { + if (handle <= handle_refs->size && + handle_refs->handle_ref_count[handle - 1]) + { + handle_refs->handle_ref_count[handle - 1]--; + } + } +} + +uint32_t drm_prime_get_handle_ref_count(struct drm_prime_handle_refs *handle_refs, + uint32_t handle) +{ + if (handle) { + if (handle <= handle_refs->size) + return handle_refs->handle_ref_count[handle - 1]; + } + return 0; +} |