17ec681f3Smrg/**************************************************************************
27ec681f3Smrg *
37ec681f3Smrg * Copyright 2010 Thomas Balling Sørensen.
47ec681f3Smrg * All Rights Reserved.
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the
87ec681f3Smrg * "Software"), to deal in the Software without restriction, including
97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish,
107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to
117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to
127ec681f3Smrg * the following conditions:
137ec681f3Smrg *
147ec681f3Smrg * The above copyright notice and this permission notice (including the
157ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions
167ec681f3Smrg * of the Software.
177ec681f3Smrg *
187ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
197ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
207ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
217ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
227ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
237ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
247ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
257ec681f3Smrg *
267ec681f3Smrg **************************************************************************/
277ec681f3Smrg
287ec681f3Smrg#include <stdio.h>
297ec681f3Smrg#include <vdpau/vdpau.h>
307ec681f3Smrg
317ec681f3Smrg#include "util/u_debug.h"
327ec681f3Smrg#include "util/u_memory.h"
337ec681f3Smrg
347ec681f3Smrg#include "vdpau_private.h"
357ec681f3Smrg
367ec681f3Smrg/**
377ec681f3Smrg * Create a VdpPresentationQueue.
387ec681f3Smrg */
397ec681f3SmrgVdpStatus
407ec681f3SmrgvlVdpPresentationQueueCreate(VdpDevice device,
417ec681f3Smrg                             VdpPresentationQueueTarget presentation_queue_target,
427ec681f3Smrg                             VdpPresentationQueue *presentation_queue)
437ec681f3Smrg{
447ec681f3Smrg   vlVdpPresentationQueue *pq = NULL;
457ec681f3Smrg   VdpStatus ret;
467ec681f3Smrg
477ec681f3Smrg   if (!presentation_queue)
487ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
497ec681f3Smrg
507ec681f3Smrg   vlVdpDevice *dev = vlGetDataHTAB(device);
517ec681f3Smrg   if (!dev)
527ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
537ec681f3Smrg
547ec681f3Smrg   vlVdpPresentationQueueTarget *pqt = vlGetDataHTAB(presentation_queue_target);
557ec681f3Smrg   if (!pqt)
567ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
577ec681f3Smrg
587ec681f3Smrg   if (dev != pqt->device)
597ec681f3Smrg      return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
607ec681f3Smrg
617ec681f3Smrg   pq = CALLOC(1, sizeof(vlVdpPresentationQueue));
627ec681f3Smrg   if (!pq)
637ec681f3Smrg      return VDP_STATUS_RESOURCES;
647ec681f3Smrg
657ec681f3Smrg   DeviceReference(&pq->device, dev);
667ec681f3Smrg   pq->drawable = pqt->drawable;
677ec681f3Smrg
687ec681f3Smrg   mtx_lock(&dev->mutex);
697ec681f3Smrg   if (!vl_compositor_init_state(&pq->cstate, dev->context)) {
707ec681f3Smrg      mtx_unlock(&dev->mutex);
717ec681f3Smrg      ret = VDP_STATUS_ERROR;
727ec681f3Smrg      goto no_compositor;
737ec681f3Smrg   }
747ec681f3Smrg   mtx_unlock(&dev->mutex);
757ec681f3Smrg
767ec681f3Smrg   *presentation_queue = vlAddDataHTAB(pq);
777ec681f3Smrg   if (*presentation_queue == 0) {
787ec681f3Smrg      ret = VDP_STATUS_ERROR;
797ec681f3Smrg      goto no_handle;
807ec681f3Smrg   }
817ec681f3Smrg
827ec681f3Smrg   return VDP_STATUS_OK;
837ec681f3Smrg
847ec681f3Smrgno_handle:
857ec681f3Smrgno_compositor:
867ec681f3Smrg   DeviceReference(&pq->device, NULL);
877ec681f3Smrg   FREE(pq);
887ec681f3Smrg   return ret;
897ec681f3Smrg}
907ec681f3Smrg
917ec681f3Smrg/**
927ec681f3Smrg * Destroy a VdpPresentationQueue.
937ec681f3Smrg */
947ec681f3SmrgVdpStatus
957ec681f3SmrgvlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue)
967ec681f3Smrg{
977ec681f3Smrg   vlVdpPresentationQueue *pq;
987ec681f3Smrg
997ec681f3Smrg   pq = vlGetDataHTAB(presentation_queue);
1007ec681f3Smrg   if (!pq)
1017ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
1027ec681f3Smrg
1037ec681f3Smrg   mtx_lock(&pq->device->mutex);
1047ec681f3Smrg   vl_compositor_cleanup_state(&pq->cstate);
1057ec681f3Smrg   mtx_unlock(&pq->device->mutex);
1067ec681f3Smrg
1077ec681f3Smrg   vlRemoveDataHTAB(presentation_queue);
1087ec681f3Smrg   DeviceReference(&pq->device, NULL);
1097ec681f3Smrg   FREE(pq);
1107ec681f3Smrg
1117ec681f3Smrg   return VDP_STATUS_OK;
1127ec681f3Smrg}
1137ec681f3Smrg
1147ec681f3Smrg/**
1157ec681f3Smrg * Configure the background color setting.
1167ec681f3Smrg */
1177ec681f3SmrgVdpStatus
1187ec681f3SmrgvlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue,
1197ec681f3Smrg                                         VdpColor *const background_color)
1207ec681f3Smrg{
1217ec681f3Smrg   vlVdpPresentationQueue *pq;
1227ec681f3Smrg   union pipe_color_union color;
1237ec681f3Smrg
1247ec681f3Smrg   if (!background_color)
1257ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
1267ec681f3Smrg
1277ec681f3Smrg   pq = vlGetDataHTAB(presentation_queue);
1287ec681f3Smrg   if (!pq)
1297ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
1307ec681f3Smrg
1317ec681f3Smrg   color.f[0] = background_color->red;
1327ec681f3Smrg   color.f[1] = background_color->green;
1337ec681f3Smrg   color.f[2] = background_color->blue;
1347ec681f3Smrg   color.f[3] = background_color->alpha;
1357ec681f3Smrg
1367ec681f3Smrg   mtx_lock(&pq->device->mutex);
1377ec681f3Smrg   vl_compositor_set_clear_color(&pq->cstate, &color);
1387ec681f3Smrg   mtx_unlock(&pq->device->mutex);
1397ec681f3Smrg
1407ec681f3Smrg   return VDP_STATUS_OK;
1417ec681f3Smrg}
1427ec681f3Smrg
1437ec681f3Smrg/**
1447ec681f3Smrg * Retrieve the current background color setting.
1457ec681f3Smrg */
1467ec681f3SmrgVdpStatus
1477ec681f3SmrgvlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue,
1487ec681f3Smrg                                         VdpColor *const background_color)
1497ec681f3Smrg{
1507ec681f3Smrg   vlVdpPresentationQueue *pq;
1517ec681f3Smrg   union pipe_color_union color;
1527ec681f3Smrg
1537ec681f3Smrg   if (!background_color)
1547ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
1557ec681f3Smrg
1567ec681f3Smrg   pq = vlGetDataHTAB(presentation_queue);
1577ec681f3Smrg   if (!pq)
1587ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
1597ec681f3Smrg
1607ec681f3Smrg   mtx_lock(&pq->device->mutex);
1617ec681f3Smrg   vl_compositor_get_clear_color(&pq->cstate, &color);
1627ec681f3Smrg   mtx_unlock(&pq->device->mutex);
1637ec681f3Smrg
1647ec681f3Smrg   background_color->red = color.f[0];
1657ec681f3Smrg   background_color->green = color.f[1];
1667ec681f3Smrg   background_color->blue = color.f[2];
1677ec681f3Smrg   background_color->alpha = color.f[3];
1687ec681f3Smrg
1697ec681f3Smrg   return VDP_STATUS_OK;
1707ec681f3Smrg}
1717ec681f3Smrg
1727ec681f3Smrg/**
1737ec681f3Smrg * Retrieve the presentation queue's "current" time.
1747ec681f3Smrg */
1757ec681f3SmrgVdpStatus
1767ec681f3SmrgvlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue,
1777ec681f3Smrg                              VdpTime *current_time)
1787ec681f3Smrg{
1797ec681f3Smrg   vlVdpPresentationQueue *pq;
1807ec681f3Smrg
1817ec681f3Smrg   if (!current_time)
1827ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
1837ec681f3Smrg
1847ec681f3Smrg   pq = vlGetDataHTAB(presentation_queue);
1857ec681f3Smrg   if (!pq)
1867ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
1877ec681f3Smrg
1887ec681f3Smrg   mtx_lock(&pq->device->mutex);
1897ec681f3Smrg   *current_time = pq->device->vscreen->get_timestamp(pq->device->vscreen,
1907ec681f3Smrg                                                      (void *)pq->drawable);
1917ec681f3Smrg   mtx_unlock(&pq->device->mutex);
1927ec681f3Smrg
1937ec681f3Smrg   return VDP_STATUS_OK;
1947ec681f3Smrg}
1957ec681f3Smrg
1967ec681f3Smrg/**
1977ec681f3Smrg * Enter a surface into the presentation queue.
1987ec681f3Smrg */
1997ec681f3SmrgVdpStatus
2007ec681f3SmrgvlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue,
2017ec681f3Smrg                              VdpOutputSurface surface,
2027ec681f3Smrg                              uint32_t clip_width,
2037ec681f3Smrg                              uint32_t clip_height,
2047ec681f3Smrg                              VdpTime  earliest_presentation_time)
2057ec681f3Smrg{
2067ec681f3Smrg   static int dump_window = -1;
2077ec681f3Smrg
2087ec681f3Smrg   vlVdpPresentationQueue *pq;
2097ec681f3Smrg   vlVdpOutputSurface *surf;
2107ec681f3Smrg
2117ec681f3Smrg   struct pipe_context *pipe;
2127ec681f3Smrg   struct pipe_resource *tex;
2137ec681f3Smrg   struct pipe_surface surf_templ, *surf_draw = NULL;
2147ec681f3Smrg   struct u_rect src_rect, dst_clip, *dirty_area;
2157ec681f3Smrg
2167ec681f3Smrg   struct vl_compositor *compositor;
2177ec681f3Smrg   struct vl_compositor_state *cstate;
2187ec681f3Smrg   struct vl_screen *vscreen;
2197ec681f3Smrg
2207ec681f3Smrg   pq = vlGetDataHTAB(presentation_queue);
2217ec681f3Smrg   if (!pq)
2227ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
2237ec681f3Smrg
2247ec681f3Smrg   surf = vlGetDataHTAB(surface);
2257ec681f3Smrg   if (!surf)
2267ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
2277ec681f3Smrg
2287ec681f3Smrg   pipe = pq->device->context;
2297ec681f3Smrg   compositor = &pq->device->compositor;
2307ec681f3Smrg   cstate = &pq->cstate;
2317ec681f3Smrg   vscreen = pq->device->vscreen;
2327ec681f3Smrg
2337ec681f3Smrg   mtx_lock(&pq->device->mutex);
2347ec681f3Smrg   if (vscreen->set_back_texture_from_output && surf->send_to_X)
2357ec681f3Smrg      vscreen->set_back_texture_from_output(vscreen, surf->surface->texture, clip_width, clip_height);
2367ec681f3Smrg   tex = vscreen->texture_from_drawable(vscreen, (void *)pq->drawable);
2377ec681f3Smrg   if (!tex) {
2387ec681f3Smrg      mtx_unlock(&pq->device->mutex);
2397ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
2407ec681f3Smrg   }
2417ec681f3Smrg
2427ec681f3Smrg   if (!vscreen->set_back_texture_from_output || !surf->send_to_X) {
2437ec681f3Smrg      dirty_area = vscreen->get_dirty_area(vscreen);
2447ec681f3Smrg
2457ec681f3Smrg      memset(&surf_templ, 0, sizeof(surf_templ));
2467ec681f3Smrg      surf_templ.format = tex->format;
2477ec681f3Smrg      surf_draw = pipe->create_surface(pipe, tex, &surf_templ);
2487ec681f3Smrg
2497ec681f3Smrg      dst_clip.x0 = 0;
2507ec681f3Smrg      dst_clip.y0 = 0;
2517ec681f3Smrg      dst_clip.x1 = clip_width ? clip_width : surf_draw->width;
2527ec681f3Smrg      dst_clip.y1 = clip_height ? clip_height : surf_draw->height;
2537ec681f3Smrg
2547ec681f3Smrg      src_rect.x0 = 0;
2557ec681f3Smrg      src_rect.y0 = 0;
2567ec681f3Smrg      src_rect.x1 = surf_draw->width;
2577ec681f3Smrg      src_rect.y1 = surf_draw->height;
2587ec681f3Smrg
2597ec681f3Smrg      vl_compositor_clear_layers(cstate);
2607ec681f3Smrg      vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL);
2617ec681f3Smrg      vl_compositor_set_dst_clip(cstate, &dst_clip);
2627ec681f3Smrg      vl_compositor_render(cstate, compositor, surf_draw, dirty_area, true);
2637ec681f3Smrg   }
2647ec681f3Smrg
2657ec681f3Smrg   vscreen->set_next_timestamp(vscreen, earliest_presentation_time);
2667ec681f3Smrg
2677ec681f3Smrg   // flush before calling flush_frontbuffer so that rendering is flushed
2687ec681f3Smrg   //  to back buffer so the texture can be copied in flush_frontbuffer
2697ec681f3Smrg   pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL);
2707ec681f3Smrg   pipe->flush(pipe, &surf->fence, 0);
2717ec681f3Smrg   pipe->screen->flush_frontbuffer(pipe->screen, pipe, tex, 0, 0,
2727ec681f3Smrg                                   vscreen->get_private(vscreen), NULL);
2737ec681f3Smrg
2747ec681f3Smrg   pq->last_surf = surf;
2757ec681f3Smrg
2767ec681f3Smrg   if (dump_window == -1) {
2777ec681f3Smrg      dump_window = debug_get_num_option("VDPAU_DUMP", 0);
2787ec681f3Smrg   }
2797ec681f3Smrg
2807ec681f3Smrg   if (dump_window) {
2817ec681f3Smrg      static unsigned int framenum = 0;
2827ec681f3Smrg      char cmd[256];
2837ec681f3Smrg
2847ec681f3Smrg      if (framenum) {
2857ec681f3Smrg         sprintf(cmd, "xwd -id %d -silent -out vdpau_frame_%08d.xwd", (int)pq->drawable, framenum);
2867ec681f3Smrg         if (system(cmd) != 0)
2877ec681f3Smrg            VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface);
2887ec681f3Smrg      }
2897ec681f3Smrg      framenum++;
2907ec681f3Smrg   }
2917ec681f3Smrg
2927ec681f3Smrg   if (!vscreen->set_back_texture_from_output || !surf->send_to_X) {
2937ec681f3Smrg      pipe_resource_reference(&tex, NULL);
2947ec681f3Smrg      pipe_surface_reference(&surf_draw, NULL);
2957ec681f3Smrg   }
2967ec681f3Smrg   mtx_unlock(&pq->device->mutex);
2977ec681f3Smrg
2987ec681f3Smrg   return VDP_STATUS_OK;
2997ec681f3Smrg}
3007ec681f3Smrg
3017ec681f3Smrg/**
3027ec681f3Smrg * Wait for a surface to finish being displayed.
3037ec681f3Smrg */
3047ec681f3SmrgVdpStatus
3057ec681f3SmrgvlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue,
3067ec681f3Smrg                                            VdpOutputSurface surface,
3077ec681f3Smrg                                            VdpTime *first_presentation_time)
3087ec681f3Smrg{
3097ec681f3Smrg   vlVdpPresentationQueue *pq;
3107ec681f3Smrg   vlVdpOutputSurface *surf;
3117ec681f3Smrg   struct pipe_screen *screen;
3127ec681f3Smrg
3137ec681f3Smrg   if (!first_presentation_time)
3147ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
3157ec681f3Smrg
3167ec681f3Smrg   pq = vlGetDataHTAB(presentation_queue);
3177ec681f3Smrg   if (!pq)
3187ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
3197ec681f3Smrg
3207ec681f3Smrg   surf = vlGetDataHTAB(surface);
3217ec681f3Smrg   if (!surf)
3227ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
3237ec681f3Smrg
3247ec681f3Smrg   mtx_lock(&pq->device->mutex);
3257ec681f3Smrg   if (surf->fence) {
3267ec681f3Smrg      screen = pq->device->vscreen->pscreen;
3277ec681f3Smrg      screen->fence_finish(screen, NULL, surf->fence, PIPE_TIMEOUT_INFINITE);
3287ec681f3Smrg      screen->fence_reference(screen, &surf->fence, NULL);
3297ec681f3Smrg   }
3307ec681f3Smrg   mtx_unlock(&pq->device->mutex);
3317ec681f3Smrg
3327ec681f3Smrg   return vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
3337ec681f3Smrg}
3347ec681f3Smrg
3357ec681f3Smrg/**
3367ec681f3Smrg * Poll the current queue status of a surface.
3377ec681f3Smrg */
3387ec681f3SmrgVdpStatus
3397ec681f3SmrgvlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue,
3407ec681f3Smrg                                         VdpOutputSurface surface,
3417ec681f3Smrg                                         VdpPresentationQueueStatus *status,
3427ec681f3Smrg                                         VdpTime *first_presentation_time)
3437ec681f3Smrg{
3447ec681f3Smrg   vlVdpPresentationQueue *pq;
3457ec681f3Smrg   vlVdpOutputSurface *surf;
3467ec681f3Smrg   struct pipe_screen *screen;
3477ec681f3Smrg
3487ec681f3Smrg   if (!(status && first_presentation_time))
3497ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
3507ec681f3Smrg
3517ec681f3Smrg   pq = vlGetDataHTAB(presentation_queue);
3527ec681f3Smrg   if (!pq)
3537ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
3547ec681f3Smrg
3557ec681f3Smrg   surf = vlGetDataHTAB(surface);
3567ec681f3Smrg   if (!surf)
3577ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
3587ec681f3Smrg
3597ec681f3Smrg   *first_presentation_time = 0;
3607ec681f3Smrg
3617ec681f3Smrg   if (!surf->fence) {
3627ec681f3Smrg      if (pq->last_surf == surf)
3637ec681f3Smrg         *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
3647ec681f3Smrg      else
3657ec681f3Smrg         *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
3667ec681f3Smrg   } else {
3677ec681f3Smrg      mtx_lock(&pq->device->mutex);
3687ec681f3Smrg      screen = pq->device->vscreen->pscreen;
3697ec681f3Smrg      if (screen->fence_finish(screen, NULL, surf->fence, 0)) {
3707ec681f3Smrg         screen->fence_reference(screen, &surf->fence, NULL);
3717ec681f3Smrg         *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
3727ec681f3Smrg         mtx_unlock(&pq->device->mutex);
3737ec681f3Smrg
3747ec681f3Smrg         // We actually need to query the timestamp of the last VSYNC event from the hardware
3757ec681f3Smrg         vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
3767ec681f3Smrg         *first_presentation_time += 1;
3777ec681f3Smrg      } else {
3787ec681f3Smrg         *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED;
3797ec681f3Smrg         mtx_unlock(&pq->device->mutex);
3807ec681f3Smrg      }
3817ec681f3Smrg   }
3827ec681f3Smrg
3837ec681f3Smrg   return VDP_STATUS_OK;
3847ec681f3Smrg}
385