Home | History | Annotate | Download | only in vdpau
      1 /**************************************************************************
      2  *
      3  * Copyright 2010 Thomas Balling Srensen.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #include <stdio.h>
     29 #include <vdpau/vdpau.h>
     30 
     31 #include "util/u_debug.h"
     32 #include "util/u_memory.h"
     33 
     34 #include "vdpau_private.h"
     35 
     36 /**
     37  * Create a VdpPresentationQueue.
     38  */
     39 VdpStatus
     40 vlVdpPresentationQueueCreate(VdpDevice device,
     41                              VdpPresentationQueueTarget presentation_queue_target,
     42                              VdpPresentationQueue *presentation_queue)
     43 {
     44    vlVdpPresentationQueue *pq = NULL;
     45    VdpStatus ret;
     46 
     47    if (!presentation_queue)
     48       return VDP_STATUS_INVALID_POINTER;
     49 
     50    vlVdpDevice *dev = vlGetDataHTAB(device);
     51    if (!dev)
     52       return VDP_STATUS_INVALID_HANDLE;
     53 
     54    vlVdpPresentationQueueTarget *pqt = vlGetDataHTAB(presentation_queue_target);
     55    if (!pqt)
     56       return VDP_STATUS_INVALID_HANDLE;
     57 
     58    if (dev != pqt->device)
     59       return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
     60 
     61    pq = CALLOC(1, sizeof(vlVdpPresentationQueue));
     62    if (!pq)
     63       return VDP_STATUS_RESOURCES;
     64 
     65    DeviceReference(&pq->device, dev);
     66    pq->drawable = pqt->drawable;
     67 
     68    pipe_mutex_lock(dev->mutex);
     69    if (!vl_compositor_init_state(&pq->cstate, dev->context)) {
     70       pipe_mutex_unlock(dev->mutex);
     71       ret = VDP_STATUS_ERROR;
     72       goto no_compositor;
     73    }
     74    pipe_mutex_unlock(dev->mutex);
     75 
     76    *presentation_queue = vlAddDataHTAB(pq);
     77    if (*presentation_queue == 0) {
     78       ret = VDP_STATUS_ERROR;
     79       goto no_handle;
     80    }
     81 
     82    return VDP_STATUS_OK;
     83 
     84 no_handle:
     85 no_compositor:
     86    DeviceReference(&pq->device, NULL);
     87    FREE(pq);
     88    return ret;
     89 }
     90 
     91 /**
     92  * Destroy a VdpPresentationQueue.
     93  */
     94 VdpStatus
     95 vlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue)
     96 {
     97    vlVdpPresentationQueue *pq;
     98 
     99    pq = vlGetDataHTAB(presentation_queue);
    100    if (!pq)
    101       return VDP_STATUS_INVALID_HANDLE;
    102 
    103    pipe_mutex_lock(pq->device->mutex);
    104    vl_compositor_cleanup_state(&pq->cstate);
    105    pipe_mutex_unlock(pq->device->mutex);
    106 
    107    vlRemoveDataHTAB(presentation_queue);
    108    DeviceReference(&pq->device, NULL);
    109    FREE(pq);
    110 
    111    return VDP_STATUS_OK;
    112 }
    113 
    114 /**
    115  * Configure the background color setting.
    116  */
    117 VdpStatus
    118 vlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue,
    119                                          VdpColor *const background_color)
    120 {
    121    vlVdpPresentationQueue *pq;
    122    union pipe_color_union color;
    123 
    124    if (!background_color)
    125       return VDP_STATUS_INVALID_POINTER;
    126 
    127    pq = vlGetDataHTAB(presentation_queue);
    128    if (!pq)
    129       return VDP_STATUS_INVALID_HANDLE;
    130 
    131    color.f[0] = background_color->red;
    132    color.f[1] = background_color->green;
    133    color.f[2] = background_color->blue;
    134    color.f[3] = background_color->alpha;
    135 
    136    pipe_mutex_lock(pq->device->mutex);
    137    vl_compositor_set_clear_color(&pq->cstate, &color);
    138    pipe_mutex_unlock(pq->device->mutex);
    139 
    140    return VDP_STATUS_OK;
    141 }
    142 
    143 /**
    144  * Retrieve the current background color setting.
    145  */
    146 VdpStatus
    147 vlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue,
    148                                          VdpColor *const background_color)
    149 {
    150    vlVdpPresentationQueue *pq;
    151    union pipe_color_union color;
    152 
    153    if (!background_color)
    154       return VDP_STATUS_INVALID_POINTER;
    155 
    156    pq = vlGetDataHTAB(presentation_queue);
    157    if (!pq)
    158       return VDP_STATUS_INVALID_HANDLE;
    159 
    160    pipe_mutex_lock(pq->device->mutex);
    161    vl_compositor_get_clear_color(&pq->cstate, &color);
    162    pipe_mutex_unlock(pq->device->mutex);
    163 
    164    background_color->red = color.f[0];
    165    background_color->green = color.f[1];
    166    background_color->blue = color.f[2];
    167    background_color->alpha = color.f[3];
    168 
    169    return VDP_STATUS_OK;
    170 }
    171 
    172 /**
    173  * Retrieve the presentation queue's "current" time.
    174  */
    175 VdpStatus
    176 vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue,
    177                               VdpTime *current_time)
    178 {
    179    vlVdpPresentationQueue *pq;
    180 
    181    if (!current_time)
    182       return VDP_STATUS_INVALID_POINTER;
    183 
    184    pq = vlGetDataHTAB(presentation_queue);
    185    if (!pq)
    186       return VDP_STATUS_INVALID_HANDLE;
    187 
    188    pipe_mutex_lock(pq->device->mutex);
    189    *current_time = pq->device->vscreen->get_timestamp(pq->device->vscreen,
    190                                                       (void *)pq->drawable);
    191    pipe_mutex_unlock(pq->device->mutex);
    192 
    193    return VDP_STATUS_OK;
    194 }
    195 
    196 /**
    197  * Enter a surface into the presentation queue.
    198  */
    199 VdpStatus
    200 vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue,
    201                               VdpOutputSurface surface,
    202                               uint32_t clip_width,
    203                               uint32_t clip_height,
    204                               VdpTime  earliest_presentation_time)
    205 {
    206    static int dump_window = -1;
    207 
    208    vlVdpPresentationQueue *pq;
    209    vlVdpOutputSurface *surf;
    210 
    211    struct pipe_context *pipe;
    212    struct pipe_resource *tex;
    213    struct pipe_surface surf_templ, *surf_draw;
    214    struct u_rect src_rect, dst_clip, *dirty_area;
    215 
    216    struct vl_compositor *compositor;
    217    struct vl_compositor_state *cstate;
    218    struct vl_screen *vscreen;
    219 
    220    pq = vlGetDataHTAB(presentation_queue);
    221    if (!pq)
    222       return VDP_STATUS_INVALID_HANDLE;
    223 
    224    surf = vlGetDataHTAB(surface);
    225    if (!surf)
    226       return VDP_STATUS_INVALID_HANDLE;
    227 
    228    pipe = pq->device->context;
    229    compositor = &pq->device->compositor;
    230    cstate = &pq->cstate;
    231    vscreen = pq->device->vscreen;
    232 
    233    pipe_mutex_lock(pq->device->mutex);
    234    if (vscreen->set_back_texture_from_output && surf->send_to_X)
    235       vscreen->set_back_texture_from_output(vscreen, surf->surface->texture, clip_width, clip_height);
    236    tex = vscreen->texture_from_drawable(vscreen, (void *)pq->drawable);
    237    if (!tex) {
    238       pipe_mutex_unlock(pq->device->mutex);
    239       return VDP_STATUS_INVALID_HANDLE;
    240    }
    241 
    242    if (!vscreen->set_back_texture_from_output || !surf->send_to_X) {
    243       dirty_area = vscreen->get_dirty_area(vscreen);
    244 
    245       memset(&surf_templ, 0, sizeof(surf_templ));
    246       surf_templ.format = tex->format;
    247       surf_draw = pipe->create_surface(pipe, tex, &surf_templ);
    248 
    249       dst_clip.x0 = 0;
    250       dst_clip.y0 = 0;
    251       dst_clip.x1 = clip_width ? clip_width : surf_draw->width;
    252       dst_clip.y1 = clip_height ? clip_height : surf_draw->height;
    253 
    254       src_rect.x0 = 0;
    255       src_rect.y0 = 0;
    256       src_rect.x1 = surf_draw->width;
    257       src_rect.y1 = surf_draw->height;
    258 
    259       vl_compositor_clear_layers(cstate);
    260       vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL);
    261       vl_compositor_set_dst_clip(cstate, &dst_clip);
    262       vl_compositor_render(cstate, compositor, surf_draw, dirty_area, true);
    263    }
    264 
    265    vscreen->set_next_timestamp(vscreen, earliest_presentation_time);
    266 
    267    // flush before calling flush_frontbuffer so that rendering is flushed
    268    //  to back buffer so the texture can be copied in flush_frontbuffer
    269    pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL);
    270    pipe->flush(pipe, &surf->fence, 0);
    271    pipe->screen->flush_frontbuffer(pipe->screen, tex, 0, 0,
    272                                    vscreen->get_private(vscreen), NULL);
    273 
    274    pq->last_surf = surf;
    275 
    276    if (dump_window == -1) {
    277       dump_window = debug_get_num_option("VDPAU_DUMP", 0);
    278    }
    279 
    280    if (dump_window) {
    281       static unsigned int framenum = 0;
    282       char cmd[256];
    283 
    284       if (framenum) {
    285          sprintf(cmd, "xwd -id %d -silent -out vdpau_frame_%08d.xwd", (int)pq->drawable, framenum);
    286          if (system(cmd) != 0)
    287             VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface);
    288       }
    289       framenum++;
    290    }
    291 
    292    if (!vscreen->set_back_texture_from_output || !surf->send_to_X) {
    293       pipe_resource_reference(&tex, NULL);
    294       pipe_surface_reference(&surf_draw, NULL);
    295    }
    296    pipe_mutex_unlock(pq->device->mutex);
    297 
    298    return VDP_STATUS_OK;
    299 }
    300 
    301 /**
    302  * Wait for a surface to finish being displayed.
    303  */
    304 VdpStatus
    305 vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue,
    306                                             VdpOutputSurface surface,
    307                                             VdpTime *first_presentation_time)
    308 {
    309    vlVdpPresentationQueue *pq;
    310    vlVdpOutputSurface *surf;
    311    struct pipe_screen *screen;
    312 
    313    if (!first_presentation_time)
    314       return VDP_STATUS_INVALID_POINTER;
    315 
    316    pq = vlGetDataHTAB(presentation_queue);
    317    if (!pq)
    318       return VDP_STATUS_INVALID_HANDLE;
    319 
    320    surf = vlGetDataHTAB(surface);
    321    if (!surf)
    322       return VDP_STATUS_INVALID_HANDLE;
    323 
    324    pipe_mutex_lock(pq->device->mutex);
    325    if (surf->fence) {
    326       screen = pq->device->vscreen->pscreen;
    327       screen->fence_finish(screen, NULL, surf->fence, PIPE_TIMEOUT_INFINITE);
    328       screen->fence_reference(screen, &surf->fence, NULL);
    329    }
    330    pipe_mutex_unlock(pq->device->mutex);
    331 
    332    return vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
    333 }
    334 
    335 /**
    336  * Poll the current queue status of a surface.
    337  */
    338 VdpStatus
    339 vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue,
    340                                          VdpOutputSurface surface,
    341                                          VdpPresentationQueueStatus *status,
    342                                          VdpTime *first_presentation_time)
    343 {
    344    vlVdpPresentationQueue *pq;
    345    vlVdpOutputSurface *surf;
    346    struct pipe_screen *screen;
    347 
    348    if (!(status && first_presentation_time))
    349       return VDP_STATUS_INVALID_POINTER;
    350 
    351    pq = vlGetDataHTAB(presentation_queue);
    352    if (!pq)
    353       return VDP_STATUS_INVALID_HANDLE;
    354 
    355    surf = vlGetDataHTAB(surface);
    356    if (!surf)
    357       return VDP_STATUS_INVALID_HANDLE;
    358 
    359    *first_presentation_time = 0;
    360 
    361    if (!surf->fence) {
    362       if (pq->last_surf == surf)
    363          *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
    364       else
    365          *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
    366    } else {
    367       pipe_mutex_lock(pq->device->mutex);
    368       screen = pq->device->vscreen->pscreen;
    369       if (screen->fence_finish(screen, NULL, surf->fence, 0)) {
    370          screen->fence_reference(screen, &surf->fence, NULL);
    371          *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
    372          pipe_mutex_unlock(pq->device->mutex);
    373 
    374          // We actually need to query the timestamp of the last VSYNC event from the hardware
    375          vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
    376          *first_presentation_time += 1;
    377       } else {
    378          *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED;
    379          pipe_mutex_unlock(pq->device->mutex);
    380       }
    381    }
    382 
    383    return VDP_STATUS_OK;
    384 }
    385