| @@ -1,393 +0,0 @@ |
| 1 | | −/* |
| 2 | | − * This file is part of mpv video player. |
| 3 | | − * |
| 4 | | − * mpv is free software; you can redistribute it and/or |
| 5 | | − * modify it under the terms of the GNU Lesser General Public |
| 6 | | − * License as published by the Free Software Foundation; either |
| 7 | | − * version 2.1 of the License, or (at your option) any later version. |
| 8 | | − * |
| 9 | | − * mpv is distributed in the hope that it will be useful, |
| 10 | | − * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | | − * GNU Lesser General Public License for more details. |
| 13 | | − * |
| 14 | | − * You should have received a copy of the GNU Lesser General Public |
| 15 | | − * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
| 16 | | − */ |
| 17 | | − |
| 18 | | −#include <fcntl.h> |
| 19 | | −#include <sys/mman.h> |
| 20 | | −#include <unistd.h> |
| 21 | | −#include <va/va_wayland.h> |
| 22 | | −#include <va/va_drmcommon.h> |
| 23 | | − |
| 24 | | −#include "present_sync.h" |
| 25 | | −#include "sub/osd.h" |
| 26 | | −#include "video/vaapi.h" |
| 27 | | −#include "wayland_common.h" |
| 28 | | − |
| 29 | | −#include "generated/wayland/linux-dmabuf-unstable-v1.h" |
| 30 | | −#include "generated/wayland/viewporter.h" |
| 31 | | − |
| 32 | | −#define VA_POOL_NUM_ALLOCATED_INIT 30 |
| 33 | | − |
| 34 | | −struct va_pool_entry { |
| 35 | | − /* key */ |
| 36 | | − VASurfaceID surface; |
| 37 | | − |
| 38 | | − VADRMPRIMESurfaceDescriptor desc; |
| 39 | | − struct wl_buffer *buffer; |
| 40 | | − struct zwp_linux_buffer_params_v1 *params; |
| 41 | | − uint32_t drm_format; |
| 42 | | −}; |
| 43 | | − |
| 44 | | −struct va_pool { |
| 45 | | − struct vo *vo; |
| 46 | | − struct va_pool_entry **entries; |
| 47 | | − int num_entries; |
| 48 | | − int num_allocated; |
| 49 | | −}; |
| 50 | | − |
| 51 | | −struct priv { |
| 52 | | − struct vo *vo; |
| 53 | | − struct mp_rect src; |
| 54 | | − struct mp_rect dst; |
| 55 | | − struct mp_osd_res osd; |
| 56 | | − struct mp_log *log; |
| 57 | | − |
| 58 | | − VADisplay display; |
| 59 | | − struct mp_vaapi_ctx *mpvaapi; |
| 60 | | − struct wl_shm_pool *solid_buffer_pool; |
| 61 | | − struct wl_buffer *solid_buffer; |
| 62 | | − struct va_pool *va_pool; |
| 63 | | −}; |
| 64 | | − |
| 65 | | −static void va_close_surface_descriptor(VADRMPRIMESurfaceDescriptor desc) |
| 66 | | −{ |
| 67 | | − for (int i = 0; i < desc.num_objects; i++) { |
| 68 | | − close(desc.objects[i].fd); |
| 69 | | − desc.objects[i].fd = 0; |
| 70 | | − } |
| 71 | | −} |
| 72 | | − |
| 73 | | −static void va_free_entry(struct va_pool_entry *entry) |
| 74 | | −{ |
| 75 | | − if (!entry) |
| 76 | | − return; |
| 77 | | − va_close_surface_descriptor(entry->desc); |
| 78 | | − if (entry->buffer) |
| 79 | | − wl_buffer_destroy(entry->buffer); |
| 80 | | − if (entry->params) |
| 81 | | − zwp_linux_buffer_params_v1_destroy(entry->params); |
| 82 | | − talloc_free(entry); |
| 83 | | −} |
| 84 | | − |
| 85 | | −static VAStatus va_export_surface_handle(VADisplay display, VASurfaceID surface, |
| 86 | | − VADRMPRIMESurfaceDescriptor *desc) |
| 87 | | −{ |
| 88 | | − return vaExportSurfaceHandle(display, surface, |
| 89 | | − VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, |
| 90 | | − VA_EXPORT_SURFACE_COMPOSED_LAYERS | |
| 91 | | − VA_EXPORT_SURFACE_READ_ONLY, |
| 92 | | − desc); |
| 93 | | −} |
| 94 | | − |
| 95 | | −static struct va_pool_entry *va_alloc_entry(struct vo *vo, struct mp_image *src) |
| 96 | | −{ |
| 97 | | − struct priv *p = vo->priv; |
| 98 | | − struct vo_wayland_state *wl = vo->wl; |
| 99 | | − VAStatus status; |
| 100 | | − struct va_pool_entry *entry = talloc(NULL, struct va_pool_entry); |
| 101 | | − memset(entry, 0, sizeof(struct va_pool_entry)); |
| 102 | | − |
| 103 | | − /* extract dmabuf surface descriptor */ |
| 104 | | − entry->surface = va_surface_id(src); |
| 105 | | − status = va_export_surface_handle(p->display, entry->surface, &entry->desc); |
| 106 | | − if (status == VA_STATUS_ERROR_INVALID_SURFACE) { |
| 107 | | − MP_VERBOSE(vo, "VA export to composed layers not supported.\n"); |
| 108 | | − va_free_entry(entry); |
| 109 | | − return NULL; |
| 110 | | − } else if (!vo_wayland_supported_format(vo, entry->desc.layers[0].drm_format)) { |
| 111 | | − MP_VERBOSE(vo, "%s is not supported.\n", |
| 112 | | − mp_tag_str(entry->desc.layers[0].drm_format)); |
| 113 | | − va_free_entry(entry); |
| 114 | | − return NULL; |
| 115 | | − } else if (!CHECK_VA_STATUS(vo, "vaExportSurfaceHandle()")) { |
| 116 | | − va_free_entry(entry); |
| 117 | | − return NULL; |
| 118 | | − } else { |
| 119 | | − int i, j, plane = 0; |
| 120 | | − |
| 121 | | − entry->params = zwp_linux_dmabuf_v1_create_params(wl->dmabuf); |
| 122 | | − for (i = 0; i < entry->desc.num_layers; i++) { |
| 123 | | − entry->drm_format = entry->desc.layers[i].drm_format; |
| 124 | | − for (j = 0; j < entry->desc.layers[i].num_planes; ++j) { |
| 125 | | − int object = entry->desc.layers[i].object_index[j]; |
| 126 | | − uint64_t modifier = entry->desc.objects[object].drm_format_modifier; |
| 127 | | − zwp_linux_buffer_params_v1_add(entry->params, |
| 128 | | − entry->desc.objects[object].fd, plane++, |
| 129 | | − entry->desc.layers[i].offset[j], |
| 130 | | − entry->desc.layers[i].pitch[j], |
| 131 | | − modifier >> 32, |
| 132 | | − modifier & 0xffffffff); |
| 133 | | − } |
| 134 | | − } |
| 135 | | − } |
| 136 | | − |
| 137 | | − entry->buffer = zwp_linux_buffer_params_v1_create_immed(entry->params, |
| 138 | | − src->params.w, |
| 139 | | − src->params.h, |
| 140 | | − entry->drm_format, 0); |
| 141 | | − |
| 142 | | − return entry; |
| 143 | | −} |
| 144 | | −static void va_pool_clean(struct va_pool *pool) |
| 145 | | −{ |
| 146 | | − if (!pool) |
| 147 | | − return; |
| 148 | | − |
| 149 | | − for (int i = 0; i < pool->num_entries; ++i) |
| 150 | | − va_free_entry(pool->entries[i]); |
| 151 | | − pool->num_entries = 0; |
| 152 | | −} |
| 153 | | − |
| 154 | | −static void va_pool_free(struct va_pool *pool) |
| 155 | | −{ |
| 156 | | − if (!pool) |
| 157 | | − return; |
| 158 | | − |
| 159 | | − va_pool_clean(pool); |
| 160 | | − talloc_free(pool); |
| 161 | | −} |
| 162 | | − |
| 163 | | −static struct va_pool *va_pool_alloc(struct vo *vo) |
| 164 | | −{ |
| 165 | | − struct va_pool *pool = talloc(NULL, struct va_pool); |
| 166 | | − memset(pool, 0, sizeof(struct va_pool)); |
| 167 | | − pool->num_allocated = VA_POOL_NUM_ALLOCATED_INIT; |
| 168 | | − pool->entries = talloc_array(pool, struct va_pool_entry *, pool->num_allocated); |
| 169 | | − memset(pool->entries, 0, pool->num_allocated * sizeof(struct va_pool_entry *)); |
| 170 | | − pool->vo = vo; |
| 171 | | − |
| 172 | | − return pool; |
| 173 | | −} |
| 174 | | − |
| 175 | | −static struct va_pool_entry *va_pool_alloc_entry(struct vo *vo, struct va_pool *pool, |
| 176 | | − struct mp_image *src) |
| 177 | | −{ |
| 178 | | − VASurfaceID surface; |
| 179 | | − |
| 180 | | − if (!pool) |
| 181 | | − return NULL; |
| 182 | | − |
| 183 | | − surface = va_surface_id(src); |
| 184 | | − for (int i = 0; i < pool->num_entries; ++i) { |
| 185 | | − struct va_pool_entry *item = pool->entries[i]; |
| 186 | | − if (item->surface == surface) |
| 187 | | − return pool->entries[i]; |
| 188 | | − } |
| 189 | | − |
| 190 | | − struct va_pool_entry *entry = va_alloc_entry(pool->vo, src); |
| 191 | | − if (!entry) |
| 192 | | − return NULL; |
| 193 | | − |
| 194 | | − if (pool->num_entries == pool->num_allocated) { |
| 195 | | − int current_num_allocated = pool->num_allocated; |
| 196 | | − pool->num_allocated *= 2; |
| 197 | | − pool->entries = talloc_realloc(pool, pool->entries, struct va_pool_entry *, |
| 198 | | − pool->num_allocated); |
| 199 | | − for (int i = current_num_allocated; i < pool->num_allocated; ++i) |
| 200 | | − pool->entries[i] = NULL; |
| 201 | | − } |
| 202 | | − pool->entries[pool->num_entries++] = entry; |
| 203 | | − |
| 204 | | − return entry; |
| 205 | | −} |
| 206 | | − |
| 207 | | −static void uninit(struct vo *vo) |
| 208 | | −{ |
| 209 | | − struct priv *p = vo->priv; |
| 210 | | − |
| 211 | | − va_pool_free(p->va_pool); |
| 212 | | − |
| 213 | | − if (p->solid_buffer_pool) |
| 214 | | − wl_shm_pool_destroy(p->solid_buffer_pool); |
| 215 | | − if (p->solid_buffer) |
| 216 | | − wl_buffer_destroy(p->solid_buffer); |
| 217 | | − |
| 218 | | − vo_wayland_uninit(vo); |
| 219 | | − |
| 220 | | − if (vo->hwdec_devs) { |
| 221 | | − hwdec_devices_remove(vo->hwdec_devs, &p->mpvaapi->hwctx); |
| 222 | | − hwdec_devices_destroy(vo->hwdec_devs); |
| 223 | | − } |
| 224 | | − if (p->mpvaapi) |
| 225 | | − va_destroy(p->mpvaapi); |
| 226 | | −} |
| 227 | | − |
| 228 | | −static int preinit(struct vo *vo) |
| 229 | | −{ |
| 230 | | − struct priv *p = vo->priv; |
| 231 | | − |
| 232 | | − p->vo = vo; |
| 233 | | − p->log = vo->log; |
| 234 | | − if (!vo_wayland_init(vo)) |
| 235 | | − return VO_ERROR; |
| 236 | | − |
| 237 | | − p->display = vaGetDisplayWl(vo->wl->display); |
| 238 | | − if (!p->display) { |
| 239 | | − MP_ERR(vo, "Unable to get the VA Display.\n"); |
| 240 | | − return VO_ERROR; |
| 241 | | − } |
| 242 | | − |
| 243 | | − p->mpvaapi = va_initialize(p->display, p->log, false); |
| 244 | | − if (!p->mpvaapi) { |
| 245 | | − vaTerminate(p->display); |
| 246 | | − p->display = NULL; |
| 247 | | − goto fail; |
| 248 | | − } |
| 249 | | − |
| 250 | | − vo->hwdec_devs = hwdec_devices_create(); |
| 251 | | − hwdec_devices_add(vo->hwdec_devs, &p->mpvaapi->hwctx); |
| 252 | | − p->va_pool = va_pool_alloc(vo); |
| 253 | | − |
| 254 | | − return 0; |
| 255 | | − |
| 256 | | −fail: |
| 257 | | − uninit(vo); |
| 258 | | − |
| 259 | | − return VO_ERROR; |
| 260 | | −} |
| 261 | | − |
| 262 | | −static int query_format(struct vo *vo, int format) |
| 263 | | −{ |
| 264 | | − return format == IMGFMT_VAAPI; |
| 265 | | −} |
| 266 | | − |
| 267 | | −static int reconfig(struct vo *vo, struct mp_image_params *params) |
| 268 | | −{ |
| 269 | | − struct priv *p = vo->priv; |
| 270 | | − struct vo_wayland_state *wl = vo->wl; |
| 271 | | − |
| 272 | | − if (!p->solid_buffer_pool) { |
| 273 | | − int width = 1; |
| 274 | | − int height = 1; |
| 275 | | − int stride = MP_ALIGN_UP(width * 4, 16); |
| 276 | | − int fd = vo_wayland_allocate_memfd(vo, stride); |
| 277 | | − if (fd < 0) |
| 278 | | − return VO_ERROR; |
| 279 | | − p->solid_buffer_pool = wl_shm_create_pool(wl->shm, fd, height * stride); |
| 280 | | − if (!p->solid_buffer_pool) |
| 281 | | − return VO_ERROR; |
| 282 | | − p->solid_buffer = wl_shm_pool_create_buffer(p->solid_buffer_pool, 0, |
| 283 | | − width, height, stride, |
| 284 | | − WL_SHM_FORMAT_XRGB8888); |
| 285 | | − if (!p->solid_buffer) |
| 286 | | − return VO_ERROR; |
| 287 | | − wl_surface_attach(wl->surface, p->solid_buffer, 0, 0); |
| 288 | | − } |
| 289 | | − |
| 290 | | − if (!vo_wayland_reconfig(vo)) |
| 291 | | − return VO_ERROR; |
| 292 | | − |
| 293 | | − return 0; |
| 294 | | −} |
| 295 | | − |
| 296 | | −static int resize(struct vo *vo) |
| 297 | | −{ |
| 298 | | − struct vo_wayland_state *wl = vo->wl; |
| 299 | | − struct priv *p = vo->priv; |
| 300 | | − |
| 301 | | − vo_wayland_set_opaque_region(wl, 0); |
| 302 | | − const int width = wl->scaling * mp_rect_w(wl->geometry); |
| 303 | | − const int height = wl->scaling * mp_rect_h(wl->geometry); |
| 304 | | − vo->dwidth = width; |
| 305 | | − vo->dheight = height; |
| 306 | | − vo_get_src_dst_rects(vo, &p->src, &p->dst, &p->osd); |
| 307 | | − |
| 308 | | − wp_viewport_set_destination(wl->viewport, |
| 309 | | − (p->dst.x0 << 1) + mp_rect_w(p->dst), |
| 310 | | − (p->dst.y0 << 1) + mp_rect_h(p->dst)); |
| 311 | | − wp_viewport_set_destination(wl->video_viewport, mp_rect_w(p->dst), |
| 312 | | − mp_rect_h(p->dst)); |
| 313 | | − wl_subsurface_set_position(wl->video_subsurface, p->dst.x0, p->dst.y0); |
| 314 | | − |
| 315 | | − vo->want_redraw = true; |
| 316 | | − |
| 317 | | − return VO_TRUE; |
| 318 | | −} |
| 319 | | − |
| 320 | | −static int control(struct vo *vo, uint32_t request, void *data) |
| 321 | | −{ |
| 322 | | − struct priv *p = vo->priv; |
| 323 | | − int events = 0; |
| 324 | | − int ret; |
| 325 | | − |
| 326 | | − switch (request) { |
| 327 | | − /* need to clean pool after seek to avoid artifacts */ |
| 328 | | − case VOCTRL_RESET: |
| 329 | | − va_pool_clean(p->va_pool); |
| 330 | | − break; |
| 331 | | − default: |
| 332 | | − break; |
| 333 | | − } |
| 334 | | − ret = vo_wayland_control(vo, &events, request, data); |
| 335 | | − if (events & VO_EVENT_RESIZE) |
| 336 | | − ret = resize(vo); |
| 337 | | − if (events & VO_EVENT_EXPOSE) |
| 338 | | − vo->want_redraw = true; |
| 339 | | − vo_event(vo, events); |
| 340 | | − |
| 341 | | − return ret; |
| 342 | | −} |
| 343 | | − |
| 344 | | −static void draw_frame(struct vo *vo, struct vo_frame *frame) |
| 345 | | −{ |
| 346 | | − struct priv *p = vo->priv; |
| 347 | | − struct vo_wayland_state *wl = vo->wl; |
| 348 | | − |
| 349 | | − if (!vo_wayland_check_visible(vo)) |
| 350 | | − return; |
| 351 | | − |
| 352 | | − struct va_pool_entry *entry = va_pool_alloc_entry(vo, p->va_pool, |
| 353 | | − frame->current); |
| 354 | | − if (!entry) |
| 355 | | − return; |
| 356 | | − |
| 357 | | − wl_surface_attach(wl->video_surface, entry->buffer, 0, 0); |
| 358 | | − wl_surface_damage_buffer(wl->video_surface, 0, 0, INT32_MAX, INT32_MAX); |
| 359 | | − wl_surface_commit(wl->video_surface); |
| 360 | | − wl_surface_commit(wl->surface); |
| 361 | | − |
| 362 | | − if (!wl->opts->disable_vsync) |
| 363 | | − vo_wayland_wait_frame(wl); |
| 364 | | − if (wl->use_present) |
| 365 | | − present_sync_swap(wl->present); |
| 366 | | −} |
| 367 | | −static void flip_page(struct vo *vo) |
| 368 | | −{ |
| 369 | | − /* no-op */ |
| 370 | | −} |
| 371 | | − |
| 372 | | −static void get_vsync(struct vo *vo, struct vo_vsync_info *info) |
| 373 | | −{ |
| 374 | | − struct vo_wayland_state *wl = vo->wl; |
| 375 | | − if (wl->use_present) |
| 376 | | − present_sync_get_info(wl->present, info); |
| 377 | | −} |
| 378 | | − |
| 379 | | −const struct vo_driver video_out_vaapi_wayland = { |
| 380 | | − .description = "VA API with Wayland video output", |
| 381 | | − .name = "vaapi-wayland", |
| 382 | | − .preinit = preinit, |
| 383 | | − .query_format = query_format, |
| 384 | | − .reconfig = reconfig, |
| 385 | | − .control = control, |
| 386 | | − .draw_frame = draw_frame, |
| 387 | | − .flip_page = flip_page, |
| 388 | | − .get_vsync = get_vsync, |
| 389 | | − .wakeup = vo_wayland_wakeup, |
| 390 | | − .wait_events = vo_wayland_wait_events, |
| 391 | | − .uninit = uninit, |
| 392 | | − .priv_size = sizeof(struct priv) |
| 393 | | −}; |