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 TUNGSTEN GRAPHICS 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    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    FREE(pq);
     87    return ret;
     88 }
     89 
     90 /**
     91  * Destroy a VdpPresentationQueue.
     92  */
     93 VdpStatus
     94 vlVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue)
     95 {
     96    vlVdpPresentationQueue *pq;
     97 
     98    pq = vlGetDataHTAB(presentation_queue);
     99    if (!pq)
    100       return VDP_STATUS_INVALID_HANDLE;
    101 
    102    pipe_mutex_lock(pq->device->mutex);
    103    vl_compositor_cleanup_state(&pq->cstate);
    104    pipe_mutex_unlock(pq->device->mutex);
    105 
    106    vlRemoveDataHTAB(presentation_queue);
    107    FREE(pq);
    108 
    109    return VDP_STATUS_OK;
    110 }
    111 
    112 /**
    113  * Configure the background color setting.
    114  */
    115 VdpStatus
    116 vlVdpPresentationQueueSetBackgroundColor(VdpPresentationQueue presentation_queue,
    117                                          VdpColor *const background_color)
    118 {
    119    vlVdpPresentationQueue *pq;
    120    union pipe_color_union color;
    121 
    122    if (!background_color)
    123       return VDP_STATUS_INVALID_POINTER;
    124 
    125    pq = vlGetDataHTAB(presentation_queue);
    126    if (!pq)
    127       return VDP_STATUS_INVALID_HANDLE;
    128 
    129    color.f[0] = background_color->red;
    130    color.f[1] = background_color->green;
    131    color.f[2] = background_color->blue;
    132    color.f[3] = background_color->alpha;
    133 
    134    pipe_mutex_lock(pq->device->mutex);
    135    vl_compositor_set_clear_color(&pq->cstate, &color);
    136    pipe_mutex_unlock(pq->device->mutex);
    137 
    138    return VDP_STATUS_OK;
    139 }
    140 
    141 /**
    142  * Retrieve the current background color setting.
    143  */
    144 VdpStatus
    145 vlVdpPresentationQueueGetBackgroundColor(VdpPresentationQueue presentation_queue,
    146                                          VdpColor *const background_color)
    147 {
    148    vlVdpPresentationQueue *pq;
    149    union pipe_color_union color;
    150 
    151    if (!background_color)
    152       return VDP_STATUS_INVALID_POINTER;
    153 
    154    pq = vlGetDataHTAB(presentation_queue);
    155    if (!pq)
    156       return VDP_STATUS_INVALID_HANDLE;
    157 
    158    pipe_mutex_lock(pq->device->mutex);
    159    vl_compositor_get_clear_color(&pq->cstate, &color);
    160    pipe_mutex_unlock(pq->device->mutex);
    161 
    162    background_color->red = color.f[0];
    163    background_color->green = color.f[1];
    164    background_color->blue = color.f[2];
    165    background_color->alpha = color.f[3];
    166 
    167    return VDP_STATUS_OK;
    168 }
    169 
    170 /**
    171  * Retrieve the presentation queue's "current" time.
    172  */
    173 VdpStatus
    174 vlVdpPresentationQueueGetTime(VdpPresentationQueue presentation_queue,
    175                               VdpTime *current_time)
    176 {
    177    vlVdpPresentationQueue *pq;
    178 
    179    if (!current_time)
    180       return VDP_STATUS_INVALID_POINTER;
    181 
    182    pq = vlGetDataHTAB(presentation_queue);
    183    if (!pq)
    184       return VDP_STATUS_INVALID_HANDLE;
    185 
    186    pipe_mutex_lock(pq->device->mutex);
    187    *current_time = vl_screen_get_timestamp(pq->device->vscreen, pq->drawable);
    188    pipe_mutex_unlock(pq->device->mutex);
    189 
    190    return VDP_STATUS_OK;
    191 }
    192 
    193 /**
    194  * Enter a surface into the presentation queue.
    195  */
    196 VdpStatus
    197 vlVdpPresentationQueueDisplay(VdpPresentationQueue presentation_queue,
    198                               VdpOutputSurface surface,
    199                               uint32_t clip_width,
    200                               uint32_t clip_height,
    201                               VdpTime  earliest_presentation_time)
    202 {
    203    static int dump_window = -1;
    204 
    205    vlVdpPresentationQueue *pq;
    206    vlVdpOutputSurface *surf;
    207 
    208    struct pipe_context *pipe;
    209    struct pipe_resource *tex;
    210    struct pipe_surface surf_templ, *surf_draw;
    211    struct u_rect src_rect, dst_clip, *dirty_area;
    212 
    213    struct vl_compositor *compositor;
    214    struct vl_compositor_state *cstate;
    215 
    216    pq = vlGetDataHTAB(presentation_queue);
    217    if (!pq)
    218       return VDP_STATUS_INVALID_HANDLE;
    219 
    220    surf = vlGetDataHTAB(surface);
    221    if (!surf)
    222       return VDP_STATUS_INVALID_HANDLE;
    223 
    224    pipe = pq->device->context;
    225    compositor = &pq->device->compositor;
    226    cstate = &pq->cstate;
    227 
    228    pipe_mutex_lock(pq->device->mutex);
    229    tex = vl_screen_texture_from_drawable(pq->device->vscreen, pq->drawable);
    230    if (!tex) {
    231       pipe_mutex_unlock(pq->device->mutex);
    232       return VDP_STATUS_INVALID_HANDLE;
    233    }
    234 
    235    dirty_area = vl_screen_get_dirty_area(pq->device->vscreen);
    236 
    237    memset(&surf_templ, 0, sizeof(surf_templ));
    238    surf_templ.format = tex->format;
    239    surf_templ.usage = PIPE_BIND_RENDER_TARGET;
    240    surf_draw = pipe->create_surface(pipe, tex, &surf_templ);
    241 
    242    surf->timestamp = (vlVdpTime)earliest_presentation_time;
    243 
    244    dst_clip.x0 = 0;
    245    dst_clip.y0 = 0;
    246    dst_clip.x1 = clip_width ? clip_width : surf_draw->width;
    247    dst_clip.y1 = clip_height ? clip_height : surf_draw->height;
    248 
    249    if (pq->device->delayed_rendering.surface == surface &&
    250        dst_clip.x1 == surf_draw->width && dst_clip.y1 == surf_draw->height) {
    251 
    252       // TODO: we correctly support the clipping here, but not the pq background color in the clipped area....
    253       cstate = pq->device->delayed_rendering.cstate;
    254       vl_compositor_set_dst_clip(cstate, &dst_clip);
    255       vlVdpResolveDelayedRendering(pq->device, surf_draw, dirty_area);
    256 
    257    } else {
    258       vlVdpResolveDelayedRendering(pq->device, NULL, NULL);
    259 
    260       src_rect.x0 = 0;
    261       src_rect.y0 = 0;
    262       src_rect.x1 = surf_draw->width;
    263       src_rect.y1 = surf_draw->height;
    264 
    265       vl_compositor_clear_layers(cstate);
    266       vl_compositor_set_rgba_layer(cstate, compositor, 0, surf->sampler_view, &src_rect, NULL, NULL);
    267       vl_compositor_set_dst_clip(cstate, &dst_clip);
    268       vl_compositor_render(cstate, compositor, surf_draw, dirty_area);
    269    }
    270 
    271    vl_screen_set_next_timestamp(pq->device->vscreen, earliest_presentation_time);
    272    pipe->screen->flush_frontbuffer
    273    (
    274       pipe->screen, tex, 0, 0,
    275       vl_screen_get_private(pq->device->vscreen)
    276    );
    277 
    278    pipe->screen->fence_reference(pipe->screen, &surf->fence, NULL);
    279    pipe->flush(pipe, &surf->fence);
    280 
    281    if (dump_window == -1) {
    282       dump_window = debug_get_num_option("VDPAU_DUMP", 0);
    283    }
    284 
    285    if (dump_window) {
    286       static unsigned int framenum = 0;
    287       char cmd[256];
    288 
    289       if (framenum) {
    290          sprintf(cmd, "xwd -id %d -silent -out vdpau_frame_%08d.xwd", (int)pq->drawable, framenum);
    291          if (system(cmd) != 0)
    292             VDPAU_MSG(VDPAU_ERR, "[VDPAU] Dumping surface %d failed.\n", surface);
    293       }
    294       framenum++;
    295    }
    296 
    297    pipe_resource_reference(&tex, NULL);
    298    pipe_surface_reference(&surf_draw, NULL);
    299    pipe_mutex_unlock(pq->device->mutex);
    300 
    301    return VDP_STATUS_OK;
    302 }
    303 
    304 /**
    305  * Wait for a surface to finish being displayed.
    306  */
    307 VdpStatus
    308 vlVdpPresentationQueueBlockUntilSurfaceIdle(VdpPresentationQueue presentation_queue,
    309                                             VdpOutputSurface surface,
    310                                             VdpTime *first_presentation_time)
    311 {
    312    vlVdpPresentationQueue *pq;
    313    vlVdpOutputSurface *surf;
    314    struct pipe_screen *screen;
    315 
    316    if (!first_presentation_time)
    317       return VDP_STATUS_INVALID_POINTER;
    318 
    319    pq = vlGetDataHTAB(presentation_queue);
    320    if (!pq)
    321       return VDP_STATUS_INVALID_HANDLE;
    322 
    323    surf = vlGetDataHTAB(surface);
    324    if (!surf)
    325       return VDP_STATUS_INVALID_HANDLE;
    326 
    327    pipe_mutex_lock(pq->device->mutex);
    328    if (surf->fence) {
    329       screen = pq->device->vscreen->pscreen;
    330       screen->fence_finish(screen, surf->fence, 0);
    331    }
    332    pipe_mutex_unlock(pq->device->mutex);
    333 
    334    return vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
    335 }
    336 
    337 /**
    338  * Poll the current queue status of a surface.
    339  */
    340 VdpStatus
    341 vlVdpPresentationQueueQuerySurfaceStatus(VdpPresentationQueue presentation_queue,
    342                                          VdpOutputSurface surface,
    343                                          VdpPresentationQueueStatus *status,
    344                                          VdpTime *first_presentation_time)
    345 {
    346    vlVdpPresentationQueue *pq;
    347    vlVdpOutputSurface *surf;
    348    struct pipe_screen *screen;
    349 
    350    if (!(status && first_presentation_time))
    351       return VDP_STATUS_INVALID_POINTER;
    352 
    353    pq = vlGetDataHTAB(presentation_queue);
    354    if (!pq)
    355       return VDP_STATUS_INVALID_HANDLE;
    356 
    357    surf = vlGetDataHTAB(surface);
    358    if (!surf)
    359       return VDP_STATUS_INVALID_HANDLE;
    360 
    361    *first_presentation_time = 0;
    362 
    363    if (!surf->fence) {
    364       *status = VDP_PRESENTATION_QUEUE_STATUS_IDLE;
    365    } else {
    366       pipe_mutex_lock(pq->device->mutex);
    367       screen = pq->device->vscreen->pscreen;
    368       if (screen->fence_signalled(screen, surf->fence)) {
    369          screen->fence_reference(screen, &surf->fence, NULL);
    370          *status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE;
    371          pipe_mutex_unlock(pq->device->mutex);
    372 
    373          // We actually need to query the timestamp of the last VSYNC event from the hardware
    374          vlVdpPresentationQueueGetTime(presentation_queue, first_presentation_time);
    375          *first_presentation_time += 1;
    376       } else {
    377          *status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED;
    378          pipe_mutex_unlock(pq->device->mutex);
    379       }
    380    }
    381 
    382    return VDP_STATUS_OK;
    383 }
    384