Home | History | Annotate | Download | only in vdpau
      1 /**************************************************************************
      2  *
      3  * Copyright 2010 Thomas Balling Srensen.
      4  * Copyright 2011 Christian Knig.
      5  * All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the
      9  * "Software"), to deal in the Software without restriction, including
     10  * without limitation the rights to use, copy, modify, merge, publish,
     11  * distribute, sub license, and/or sell copies of the Software, and to
     12  * permit persons to whom the Software is furnished to do so, subject to
     13  * the following conditions:
     14  *
     15  * The above copyright notice and this permission notice (including the
     16  * next paragraph) shall be included in all copies or substantial portions
     17  * of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     22  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26  *
     27  **************************************************************************/
     28 
     29 #include <vdpau/vdpau.h>
     30 
     31 #include "util/u_debug.h"
     32 #include "util/u_memory.h"
     33 #include "util/u_sampler.h"
     34 #include "util/u_format.h"
     35 #include "util/u_surface.h"
     36 
     37 #include "vl/vl_csc.h"
     38 
     39 #include "state_tracker/drm_driver.h"
     40 
     41 #include "vdpau_private.h"
     42 
     43 /**
     44  * Create a VdpOutputSurface.
     45  */
     46 VdpStatus
     47 vlVdpOutputSurfaceCreate(VdpDevice device,
     48                          VdpRGBAFormat rgba_format,
     49                          uint32_t width, uint32_t height,
     50                          VdpOutputSurface  *surface)
     51 {
     52    struct pipe_context *pipe;
     53    struct pipe_resource res_tmpl, *res;
     54    struct pipe_sampler_view sv_templ;
     55    struct pipe_surface surf_templ;
     56 
     57    vlVdpOutputSurface *vlsurface = NULL;
     58 
     59    if (!(width && height))
     60       return VDP_STATUS_INVALID_SIZE;
     61 
     62    vlVdpDevice *dev = vlGetDataHTAB(device);
     63    if (!dev)
     64       return VDP_STATUS_INVALID_HANDLE;
     65 
     66    pipe = dev->context;
     67    if (!pipe)
     68       return VDP_STATUS_INVALID_HANDLE;
     69 
     70    vlsurface = CALLOC(1, sizeof(vlVdpOutputSurface));
     71    if (!vlsurface)
     72       return VDP_STATUS_RESOURCES;
     73 
     74    DeviceReference(&vlsurface->device, dev);
     75 
     76    memset(&res_tmpl, 0, sizeof(res_tmpl));
     77 
     78    /*
     79     * The output won't look correctly when this buffer is send to X,
     80     * if the VDPAU RGB component order doesn't match the X11 one so
     81     * we only allow the X11 format
     82     */
     83    vlsurface->send_to_X = rgba_format == VDP_RGBA_FORMAT_B8G8R8A8;
     84 
     85    res_tmpl.target = PIPE_TEXTURE_2D;
     86    res_tmpl.format = VdpFormatRGBAToPipe(rgba_format);
     87    res_tmpl.width0 = width;
     88    res_tmpl.height0 = height;
     89    res_tmpl.depth0 = 1;
     90    res_tmpl.array_size = 1;
     91    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET |
     92                    PIPE_BIND_SHARED | PIPE_BIND_SCANOUT;
     93    res_tmpl.usage = PIPE_USAGE_DEFAULT;
     94 
     95    pipe_mutex_lock(dev->mutex);
     96 
     97    if (!CheckSurfaceParams(pipe->screen, &res_tmpl))
     98       goto err_unlock;
     99 
    100    res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    101    if (!res)
    102       goto err_unlock;
    103 
    104    vlVdpDefaultSamplerViewTemplate(&sv_templ, res);
    105    vlsurface->sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
    106    if (!vlsurface->sampler_view)
    107       goto err_resource;
    108 
    109    memset(&surf_templ, 0, sizeof(surf_templ));
    110    surf_templ.format = res->format;
    111    vlsurface->surface = pipe->create_surface(pipe, res, &surf_templ);
    112    if (!vlsurface->surface)
    113       goto err_resource;
    114 
    115    *surface = vlAddDataHTAB(vlsurface);
    116    if (*surface == 0)
    117       goto err_resource;
    118 
    119    pipe_resource_reference(&res, NULL);
    120 
    121    if (!vl_compositor_init_state(&vlsurface->cstate, pipe))
    122       goto err_resource;
    123 
    124    vl_compositor_reset_dirty_area(&vlsurface->dirty_area);
    125    pipe_mutex_unlock(dev->mutex);
    126 
    127    return VDP_STATUS_OK;
    128 
    129 err_resource:
    130    pipe_sampler_view_reference(&vlsurface->sampler_view, NULL);
    131    pipe_surface_reference(&vlsurface->surface, NULL);
    132    pipe_resource_reference(&res, NULL);
    133 err_unlock:
    134    pipe_mutex_unlock(dev->mutex);
    135    DeviceReference(&vlsurface->device, NULL);
    136    FREE(vlsurface);
    137    return VDP_STATUS_ERROR;
    138 }
    139 
    140 /**
    141  * Destroy a VdpOutputSurface.
    142  */
    143 VdpStatus
    144 vlVdpOutputSurfaceDestroy(VdpOutputSurface surface)
    145 {
    146    vlVdpOutputSurface *vlsurface;
    147    struct pipe_context *pipe;
    148 
    149    vlsurface = vlGetDataHTAB(surface);
    150    if (!vlsurface)
    151       return VDP_STATUS_INVALID_HANDLE;
    152 
    153    pipe = vlsurface->device->context;
    154 
    155    pipe_mutex_lock(vlsurface->device->mutex);
    156 
    157    pipe_surface_reference(&vlsurface->surface, NULL);
    158    pipe_sampler_view_reference(&vlsurface->sampler_view, NULL);
    159    pipe->screen->fence_reference(pipe->screen, &vlsurface->fence, NULL);
    160    vl_compositor_cleanup_state(&vlsurface->cstate);
    161    pipe_mutex_unlock(vlsurface->device->mutex);
    162 
    163    vlRemoveDataHTAB(surface);
    164    DeviceReference(&vlsurface->device, NULL);
    165    FREE(vlsurface);
    166 
    167    return VDP_STATUS_OK;
    168 }
    169 
    170 /**
    171  * Retrieve the parameters used to create a VdpOutputSurface.
    172  */
    173 VdpStatus
    174 vlVdpOutputSurfaceGetParameters(VdpOutputSurface surface,
    175                                 VdpRGBAFormat *rgba_format,
    176                                 uint32_t *width, uint32_t *height)
    177 {
    178    vlVdpOutputSurface *vlsurface;
    179 
    180    vlsurface = vlGetDataHTAB(surface);
    181    if (!vlsurface)
    182       return VDP_STATUS_INVALID_HANDLE;
    183 
    184    *rgba_format = PipeToFormatRGBA(vlsurface->sampler_view->texture->format);
    185    *width = vlsurface->sampler_view->texture->width0;
    186    *height = vlsurface->sampler_view->texture->height0;
    187 
    188    return VDP_STATUS_OK;
    189 }
    190 
    191 /**
    192  * Copy image data from a VdpOutputSurface to application memory in the
    193  * surface's native format.
    194  */
    195 VdpStatus
    196 vlVdpOutputSurfaceGetBitsNative(VdpOutputSurface surface,
    197                                 VdpRect const *source_rect,
    198                                 void *const *destination_data,
    199                                 uint32_t const *destination_pitches)
    200 {
    201    vlVdpOutputSurface *vlsurface;
    202    struct pipe_context *pipe;
    203    struct pipe_resource *res;
    204    struct pipe_box box;
    205    struct pipe_transfer *transfer;
    206    uint8_t *map;
    207 
    208    vlsurface = vlGetDataHTAB(surface);
    209    if (!vlsurface)
    210       return VDP_STATUS_INVALID_HANDLE;
    211 
    212    pipe = vlsurface->device->context;
    213    if (!pipe)
    214       return VDP_STATUS_INVALID_HANDLE;
    215 
    216    if (!destination_data || !destination_pitches)
    217        return VDP_STATUS_INVALID_POINTER;
    218 
    219    pipe_mutex_lock(vlsurface->device->mutex);
    220 
    221    res = vlsurface->sampler_view->texture;
    222    box = RectToPipeBox(source_rect, res);
    223    map = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box, &transfer);
    224    if (!map) {
    225       pipe_mutex_unlock(vlsurface->device->mutex);
    226       return VDP_STATUS_RESOURCES;
    227    }
    228 
    229    util_copy_rect(*destination_data, res->format, *destination_pitches, 0, 0,
    230                   box.width, box.height, map, transfer->stride, 0, 0);
    231 
    232    pipe_transfer_unmap(pipe, transfer);
    233    pipe_mutex_unlock(vlsurface->device->mutex);
    234 
    235    return VDP_STATUS_OK;
    236 }
    237 
    238 /**
    239  * Copy image data from application memory in the surface's native format to
    240  * a VdpOutputSurface.
    241  */
    242 VdpStatus
    243 vlVdpOutputSurfacePutBitsNative(VdpOutputSurface surface,
    244                                 void const *const *source_data,
    245                                 uint32_t const *source_pitches,
    246                                 VdpRect const *destination_rect)
    247 {
    248    vlVdpOutputSurface *vlsurface;
    249    struct pipe_box dst_box;
    250    struct pipe_context *pipe;
    251 
    252    vlsurface = vlGetDataHTAB(surface);
    253    if (!vlsurface)
    254       return VDP_STATUS_INVALID_HANDLE;
    255 
    256    pipe = vlsurface->device->context;
    257    if (!pipe)
    258       return VDP_STATUS_INVALID_HANDLE;
    259 
    260    if (!source_data || !source_pitches)
    261        return VDP_STATUS_INVALID_POINTER;
    262 
    263    pipe_mutex_lock(vlsurface->device->mutex);
    264 
    265    dst_box = RectToPipeBox(destination_rect, vlsurface->sampler_view->texture);
    266    pipe->texture_subdata(pipe, vlsurface->sampler_view->texture, 0,
    267                          PIPE_TRANSFER_WRITE, &dst_box, *source_data,
    268                          *source_pitches, 0);
    269    pipe_mutex_unlock(vlsurface->device->mutex);
    270 
    271    return VDP_STATUS_OK;
    272 }
    273 
    274 /**
    275  * Copy image data from application memory in a specific indexed format to
    276  * a VdpOutputSurface.
    277  */
    278 VdpStatus
    279 vlVdpOutputSurfacePutBitsIndexed(VdpOutputSurface surface,
    280                                  VdpIndexedFormat source_indexed_format,
    281                                  void const *const *source_data,
    282                                  uint32_t const *source_pitch,
    283                                  VdpRect const *destination_rect,
    284                                  VdpColorTableFormat color_table_format,
    285                                  void const *color_table)
    286 {
    287    vlVdpOutputSurface *vlsurface;
    288    struct pipe_context *context;
    289    struct vl_compositor *compositor;
    290    struct vl_compositor_state *cstate;
    291 
    292    enum pipe_format index_format;
    293    enum pipe_format colortbl_format;
    294 
    295    struct pipe_resource *res, res_tmpl;
    296    struct pipe_sampler_view sv_tmpl;
    297    struct pipe_sampler_view *sv_idx = NULL, *sv_tbl = NULL;
    298 
    299    struct pipe_box box;
    300    struct u_rect dst_rect;
    301 
    302    vlsurface = vlGetDataHTAB(surface);
    303    if (!vlsurface)
    304       return VDP_STATUS_INVALID_HANDLE;
    305 
    306    context = vlsurface->device->context;
    307    compositor = &vlsurface->device->compositor;
    308    cstate = &vlsurface->cstate;
    309 
    310    index_format = FormatIndexedToPipe(source_indexed_format);
    311    if (index_format == PIPE_FORMAT_NONE)
    312        return VDP_STATUS_INVALID_INDEXED_FORMAT;
    313 
    314    if (!source_data || !source_pitch)
    315        return VDP_STATUS_INVALID_POINTER;
    316 
    317    colortbl_format = FormatColorTableToPipe(color_table_format);
    318    if (colortbl_format == PIPE_FORMAT_NONE)
    319        return VDP_STATUS_INVALID_COLOR_TABLE_FORMAT;
    320 
    321    if (!color_table)
    322        return VDP_STATUS_INVALID_POINTER;
    323 
    324    memset(&res_tmpl, 0, sizeof(res_tmpl));
    325    res_tmpl.target = PIPE_TEXTURE_2D;
    326    res_tmpl.format = index_format;
    327 
    328    if (destination_rect) {
    329       res_tmpl.width0 = abs(destination_rect->x0-destination_rect->x1);
    330       res_tmpl.height0 = abs(destination_rect->y0-destination_rect->y1);
    331    } else {
    332       res_tmpl.width0 = vlsurface->surface->texture->width0;
    333       res_tmpl.height0 = vlsurface->surface->texture->height0;
    334    }
    335    res_tmpl.depth0 = 1;
    336    res_tmpl.array_size = 1;
    337    res_tmpl.usage = PIPE_USAGE_STAGING;
    338    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
    339 
    340    pipe_mutex_lock(vlsurface->device->mutex);
    341 
    342    if (!CheckSurfaceParams(context->screen, &res_tmpl))
    343       goto error_resource;
    344 
    345    res = context->screen->resource_create(context->screen, &res_tmpl);
    346    if (!res)
    347       goto error_resource;
    348 
    349    box.x = box.y = box.z = 0;
    350    box.width = res->width0;
    351    box.height = res->height0;
    352    box.depth = res->depth0;
    353 
    354    context->texture_subdata(context, res, 0, PIPE_TRANSFER_WRITE, &box,
    355                             source_data[0], source_pitch[0],
    356                             source_pitch[0] * res->height0);
    357 
    358    memset(&sv_tmpl, 0, sizeof(sv_tmpl));
    359    u_sampler_view_default_template(&sv_tmpl, res, res->format);
    360 
    361    sv_idx = context->create_sampler_view(context, res, &sv_tmpl);
    362    pipe_resource_reference(&res, NULL);
    363 
    364    if (!sv_idx)
    365       goto error_resource;
    366 
    367    memset(&res_tmpl, 0, sizeof(res_tmpl));
    368    res_tmpl.target = PIPE_TEXTURE_1D;
    369    res_tmpl.format = colortbl_format;
    370    res_tmpl.width0 = 1 << util_format_get_component_bits(
    371       index_format, UTIL_FORMAT_COLORSPACE_RGB, 0);
    372    res_tmpl.height0 = 1;
    373    res_tmpl.depth0 = 1;
    374    res_tmpl.array_size = 1;
    375    res_tmpl.usage = PIPE_USAGE_STAGING;
    376    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
    377 
    378    res = context->screen->resource_create(context->screen, &res_tmpl);
    379    if (!res)
    380       goto error_resource;
    381 
    382    box.x = box.y = box.z = 0;
    383    box.width = res->width0;
    384    box.height = res->height0;
    385    box.depth = res->depth0;
    386 
    387    context->texture_subdata(context, res, 0, PIPE_TRANSFER_WRITE, &box, color_table,
    388                             util_format_get_stride(colortbl_format, res->width0), 0);
    389 
    390    memset(&sv_tmpl, 0, sizeof(sv_tmpl));
    391    u_sampler_view_default_template(&sv_tmpl, res, res->format);
    392 
    393    sv_tbl = context->create_sampler_view(context, res, &sv_tmpl);
    394    pipe_resource_reference(&res, NULL);
    395 
    396    if (!sv_tbl)
    397       goto error_resource;
    398 
    399    vl_compositor_clear_layers(cstate);
    400    vl_compositor_set_palette_layer(cstate, compositor, 0, sv_idx, sv_tbl, NULL, NULL, false);
    401    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
    402    vl_compositor_render(cstate, compositor, vlsurface->surface, &vlsurface->dirty_area, false);
    403 
    404    pipe_sampler_view_reference(&sv_idx, NULL);
    405    pipe_sampler_view_reference(&sv_tbl, NULL);
    406    pipe_mutex_unlock(vlsurface->device->mutex);
    407 
    408    return VDP_STATUS_OK;
    409 
    410 error_resource:
    411    pipe_sampler_view_reference(&sv_idx, NULL);
    412    pipe_sampler_view_reference(&sv_tbl, NULL);
    413    pipe_mutex_unlock(vlsurface->device->mutex);
    414    return VDP_STATUS_RESOURCES;
    415 }
    416 
    417 /**
    418  * Copy image data from application memory in a specific YCbCr format to
    419  * a VdpOutputSurface.
    420  */
    421 VdpStatus
    422 vlVdpOutputSurfacePutBitsYCbCr(VdpOutputSurface surface,
    423                                VdpYCbCrFormat source_ycbcr_format,
    424                                void const *const *source_data,
    425                                uint32_t const *source_pitches,
    426                                VdpRect const *destination_rect,
    427                                VdpCSCMatrix const *csc_matrix)
    428 {
    429    vlVdpOutputSurface *vlsurface;
    430    struct vl_compositor *compositor;
    431    struct vl_compositor_state *cstate;
    432 
    433    struct pipe_context *pipe;
    434    enum pipe_format format;
    435    struct pipe_video_buffer vtmpl, *vbuffer;
    436    struct u_rect dst_rect;
    437    struct pipe_sampler_view **sampler_views;
    438 
    439    unsigned i;
    440 
    441    vlsurface = vlGetDataHTAB(surface);
    442    if (!vlsurface)
    443       return VDP_STATUS_INVALID_HANDLE;
    444 
    445 
    446    pipe = vlsurface->device->context;
    447    compositor = &vlsurface->device->compositor;
    448    cstate = &vlsurface->cstate;
    449 
    450    format = FormatYCBCRToPipe(source_ycbcr_format);
    451    if (format == PIPE_FORMAT_NONE)
    452        return VDP_STATUS_INVALID_Y_CB_CR_FORMAT;
    453 
    454    if (!source_data || !source_pitches)
    455        return VDP_STATUS_INVALID_POINTER;
    456 
    457    pipe_mutex_lock(vlsurface->device->mutex);
    458    memset(&vtmpl, 0, sizeof(vtmpl));
    459    vtmpl.buffer_format = format;
    460    vtmpl.chroma_format = FormatYCBCRToPipeChroma(source_ycbcr_format);
    461 
    462    if (destination_rect) {
    463       vtmpl.width = abs(destination_rect->x0-destination_rect->x1);
    464       vtmpl.height = abs(destination_rect->y0-destination_rect->y1);
    465    } else {
    466       vtmpl.width = vlsurface->surface->texture->width0;
    467       vtmpl.height = vlsurface->surface->texture->height0;
    468    }
    469 
    470    vbuffer = pipe->create_video_buffer(pipe, &vtmpl);
    471    if (!vbuffer) {
    472       pipe_mutex_unlock(vlsurface->device->mutex);
    473       return VDP_STATUS_RESOURCES;
    474    }
    475 
    476    sampler_views = vbuffer->get_sampler_view_planes(vbuffer);
    477    if (!sampler_views) {
    478       vbuffer->destroy(vbuffer);
    479       pipe_mutex_unlock(vlsurface->device->mutex);
    480       return VDP_STATUS_RESOURCES;
    481    }
    482 
    483    for (i = 0; i < 3; ++i) {
    484       struct pipe_sampler_view *sv = sampler_views[i];
    485       if (!sv) continue;
    486 
    487       struct pipe_box dst_box = {
    488          0, 0, 0,
    489          sv->texture->width0, sv->texture->height0, 1
    490       };
    491 
    492       pipe->texture_subdata(pipe, sv->texture, 0, PIPE_TRANSFER_WRITE, &dst_box,
    493                             source_data[i], source_pitches[i], 0);
    494    }
    495 
    496    if (!csc_matrix) {
    497       vl_csc_matrix csc;
    498       vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &csc);
    499       if (!vl_compositor_set_csc_matrix(cstate, (const vl_csc_matrix*)&csc, 1.0f, 0.0f))
    500          goto err_csc_matrix;
    501    } else {
    502       if (!vl_compositor_set_csc_matrix(cstate, csc_matrix, 1.0f, 0.0f))
    503          goto err_csc_matrix;
    504    }
    505 
    506    vl_compositor_clear_layers(cstate);
    507    vl_compositor_set_buffer_layer(cstate, compositor, 0, vbuffer, NULL, NULL, VL_COMPOSITOR_WEAVE);
    508    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
    509    vl_compositor_render(cstate, compositor, vlsurface->surface, &vlsurface->dirty_area, false);
    510 
    511    vbuffer->destroy(vbuffer);
    512    pipe_mutex_unlock(vlsurface->device->mutex);
    513 
    514    return VDP_STATUS_OK;
    515 err_csc_matrix:
    516    vbuffer->destroy(vbuffer);
    517    pipe_mutex_unlock(vlsurface->device->mutex);
    518    return VDP_STATUS_ERROR;
    519 }
    520 
    521 static unsigned
    522 BlendFactorToPipe(VdpOutputSurfaceRenderBlendFactor factor)
    523 {
    524    switch (factor) {
    525    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO:
    526       return PIPE_BLENDFACTOR_ZERO;
    527    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE:
    528       return PIPE_BLENDFACTOR_ONE;
    529    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_COLOR:
    530       return PIPE_BLENDFACTOR_SRC_COLOR;
    531    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
    532       return PIPE_BLENDFACTOR_INV_SRC_COLOR;
    533    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA:
    534       return PIPE_BLENDFACTOR_SRC_ALPHA;
    535    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
    536       return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
    537    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_ALPHA:
    538       return PIPE_BLENDFACTOR_DST_ALPHA;
    539    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
    540       return PIPE_BLENDFACTOR_INV_DST_ALPHA;
    541    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_DST_COLOR:
    542       return PIPE_BLENDFACTOR_DST_COLOR;
    543    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
    544       return PIPE_BLENDFACTOR_INV_DST_COLOR;
    545    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA_SATURATE:
    546       return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
    547    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_COLOR:
    548       return PIPE_BLENDFACTOR_CONST_COLOR;
    549    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
    550       return PIPE_BLENDFACTOR_INV_CONST_COLOR;
    551    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_CONSTANT_ALPHA:
    552       return PIPE_BLENDFACTOR_CONST_ALPHA;
    553    case VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
    554       return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
    555    default:
    556       assert(0);
    557       return PIPE_BLENDFACTOR_ONE;
    558    }
    559 }
    560 
    561 static unsigned
    562 BlendEquationToPipe(VdpOutputSurfaceRenderBlendEquation equation)
    563 {
    564    switch (equation) {
    565    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_SUBTRACT:
    566       return PIPE_BLEND_SUBTRACT;
    567    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_REVERSE_SUBTRACT:
    568       return PIPE_BLEND_REVERSE_SUBTRACT;
    569    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD:
    570       return PIPE_BLEND_ADD;
    571    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MIN:
    572       return PIPE_BLEND_MIN;
    573    case VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_MAX:
    574       return PIPE_BLEND_MAX;
    575    default:
    576       assert(0);
    577       return PIPE_BLEND_ADD;
    578    }
    579 }
    580 
    581 static void *
    582 BlenderToPipe(struct pipe_context *context,
    583               VdpOutputSurfaceRenderBlendState const *blend_state)
    584 {
    585    struct pipe_blend_state blend;
    586 
    587    memset(&blend, 0, sizeof blend);
    588    blend.independent_blend_enable = 0;
    589 
    590    if (blend_state) {
    591       blend.rt[0].blend_enable = 1;
    592       blend.rt[0].rgb_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_color);
    593       blend.rt[0].rgb_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_color);
    594       blend.rt[0].alpha_src_factor = BlendFactorToPipe(blend_state->blend_factor_source_alpha);
    595       blend.rt[0].alpha_dst_factor = BlendFactorToPipe(blend_state->blend_factor_destination_alpha);
    596       blend.rt[0].rgb_func = BlendEquationToPipe(blend_state->blend_equation_color);
    597       blend.rt[0].alpha_func = BlendEquationToPipe(blend_state->blend_equation_alpha);
    598    } else {
    599       blend.rt[0].blend_enable = 0;
    600    }
    601 
    602    blend.logicop_enable = 0;
    603    blend.logicop_func = PIPE_LOGICOP_CLEAR;
    604    blend.rt[0].colormask = PIPE_MASK_RGBA;
    605    blend.dither = 0;
    606 
    607    return context->create_blend_state(context, &blend);
    608 }
    609 
    610 static struct vertex4f *
    611 ColorsToPipe(VdpColor const *colors, uint32_t flags, struct vertex4f result[4])
    612 {
    613    unsigned i;
    614    struct vertex4f *dst = result;
    615 
    616    if (!colors)
    617       return NULL;
    618 
    619    for (i = 0; i < 4; ++i) {
    620       dst->x = colors->red;
    621       dst->y = colors->green;
    622       dst->z = colors->blue;
    623       dst->w = colors->alpha;
    624 
    625       ++dst;
    626       if (flags & VDP_OUTPUT_SURFACE_RENDER_COLOR_PER_VERTEX)
    627          ++colors;
    628    }
    629    return result;
    630 }
    631 
    632 /**
    633  * Composite a sub-rectangle of a VdpOutputSurface into a sub-rectangle of
    634  * another VdpOutputSurface; Output Surface object VdpOutputSurface.
    635  */
    636 VdpStatus
    637 vlVdpOutputSurfaceRenderOutputSurface(VdpOutputSurface destination_surface,
    638                                       VdpRect const *destination_rect,
    639                                       VdpOutputSurface source_surface,
    640                                       VdpRect const *source_rect,
    641                                       VdpColor const *colors,
    642                                       VdpOutputSurfaceRenderBlendState const *blend_state,
    643                                       uint32_t flags)
    644 {
    645    vlVdpOutputSurface *dst_vlsurface;
    646 
    647    struct pipe_context *context;
    648    struct pipe_sampler_view *src_sv;
    649    struct vl_compositor *compositor;
    650    struct vl_compositor_state *cstate;
    651 
    652    struct u_rect src_rect, dst_rect;
    653 
    654    struct vertex4f vlcolors[4];
    655    void *blend;
    656 
    657    dst_vlsurface = vlGetDataHTAB(destination_surface);
    658    if (!dst_vlsurface)
    659       return VDP_STATUS_INVALID_HANDLE;
    660 
    661    if (source_surface == VDP_INVALID_HANDLE) {
    662       src_sv = dst_vlsurface->device->dummy_sv;
    663 
    664    } else {
    665       vlVdpOutputSurface *src_vlsurface = vlGetDataHTAB(source_surface);
    666       if (!src_vlsurface)
    667          return VDP_STATUS_INVALID_HANDLE;
    668 
    669       if (dst_vlsurface->device != src_vlsurface->device)
    670          return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
    671 
    672       src_sv = src_vlsurface->sampler_view;
    673    }
    674 
    675    pipe_mutex_lock(dst_vlsurface->device->mutex);
    676 
    677    context = dst_vlsurface->device->context;
    678    compositor = &dst_vlsurface->device->compositor;
    679    cstate = &dst_vlsurface->cstate;
    680 
    681    blend = BlenderToPipe(context, blend_state);
    682 
    683    vl_compositor_clear_layers(cstate);
    684    vl_compositor_set_layer_blend(cstate, 0, blend, false);
    685    vl_compositor_set_rgba_layer(cstate, compositor, 0, src_sv,
    686                                 RectToPipe(source_rect, &src_rect), NULL,
    687                                 ColorsToPipe(colors, flags, vlcolors));
    688    STATIC_ASSERT(VL_COMPOSITOR_ROTATE_0 == VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
    689    STATIC_ASSERT(VL_COMPOSITOR_ROTATE_90 == VDP_OUTPUT_SURFACE_RENDER_ROTATE_90);
    690    STATIC_ASSERT(VL_COMPOSITOR_ROTATE_180 == VDP_OUTPUT_SURFACE_RENDER_ROTATE_180);
    691    STATIC_ASSERT(VL_COMPOSITOR_ROTATE_270 == VDP_OUTPUT_SURFACE_RENDER_ROTATE_270);
    692    vl_compositor_set_layer_rotation(cstate, 0, flags & 3);
    693    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
    694    vl_compositor_render(cstate, compositor, dst_vlsurface->surface, &dst_vlsurface->dirty_area, false);
    695 
    696    context->delete_blend_state(context, blend);
    697    pipe_mutex_unlock(dst_vlsurface->device->mutex);
    698 
    699    return VDP_STATUS_OK;
    700 }
    701 
    702 /**
    703  * Composite a sub-rectangle of a VdpBitmapSurface into a sub-rectangle of
    704  * a VdpOutputSurface; Output Surface object VdpOutputSurface.
    705  */
    706 VdpStatus
    707 vlVdpOutputSurfaceRenderBitmapSurface(VdpOutputSurface destination_surface,
    708                                       VdpRect const *destination_rect,
    709                                       VdpBitmapSurface source_surface,
    710                                       VdpRect const *source_rect,
    711                                       VdpColor const *colors,
    712                                       VdpOutputSurfaceRenderBlendState const *blend_state,
    713                                       uint32_t flags)
    714 {
    715    vlVdpOutputSurface *dst_vlsurface;
    716 
    717    struct pipe_context *context;
    718    struct pipe_sampler_view *src_sv;
    719    struct vl_compositor *compositor;
    720    struct vl_compositor_state *cstate;
    721 
    722    struct u_rect src_rect, dst_rect;
    723 
    724    struct vertex4f vlcolors[4];
    725    void *blend;
    726 
    727    dst_vlsurface = vlGetDataHTAB(destination_surface);
    728    if (!dst_vlsurface)
    729       return VDP_STATUS_INVALID_HANDLE;
    730 
    731    if (source_surface == VDP_INVALID_HANDLE) {
    732       src_sv = dst_vlsurface->device->dummy_sv;
    733 
    734    } else {
    735       vlVdpBitmapSurface *src_vlsurface = vlGetDataHTAB(source_surface);
    736       if (!src_vlsurface)
    737          return VDP_STATUS_INVALID_HANDLE;
    738 
    739       if (dst_vlsurface->device != src_vlsurface->device)
    740          return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
    741 
    742       src_sv = src_vlsurface->sampler_view;
    743    }
    744 
    745    context = dst_vlsurface->device->context;
    746    compositor = &dst_vlsurface->device->compositor;
    747    cstate = &dst_vlsurface->cstate;
    748 
    749    pipe_mutex_lock(dst_vlsurface->device->mutex);
    750 
    751    blend = BlenderToPipe(context, blend_state);
    752 
    753    vl_compositor_clear_layers(cstate);
    754    vl_compositor_set_layer_blend(cstate, 0, blend, false);
    755    vl_compositor_set_rgba_layer(cstate, compositor, 0, src_sv,
    756                                 RectToPipe(source_rect, &src_rect), NULL,
    757                                 ColorsToPipe(colors, flags, vlcolors));
    758    vl_compositor_set_layer_rotation(cstate, 0, flags & 3);
    759    vl_compositor_set_layer_dst_area(cstate, 0, RectToPipe(destination_rect, &dst_rect));
    760    vl_compositor_render(cstate, compositor, dst_vlsurface->surface, &dst_vlsurface->dirty_area, false);
    761 
    762    context->delete_blend_state(context, blend);
    763    pipe_mutex_unlock(dst_vlsurface->device->mutex);
    764 
    765    return VDP_STATUS_OK;
    766 }
    767 
    768 struct pipe_resource *vlVdpOutputSurfaceGallium(VdpOutputSurface surface)
    769 {
    770    vlVdpOutputSurface *vlsurface;
    771 
    772    vlsurface = vlGetDataHTAB(surface);
    773    if (!vlsurface || !vlsurface->surface)
    774       return NULL;
    775 
    776    pipe_mutex_lock(vlsurface->device->mutex);
    777    vlsurface->device->context->flush(vlsurface->device->context, NULL, 0);
    778    pipe_mutex_unlock(vlsurface->device->mutex);
    779 
    780    return vlsurface->surface->texture;
    781 }
    782 
    783 VdpStatus vlVdpOutputSurfaceDMABuf(VdpOutputSurface surface,
    784                                    struct VdpSurfaceDMABufDesc *result)
    785 {
    786    vlVdpOutputSurface *vlsurface;
    787    struct pipe_screen *pscreen;
    788    struct winsys_handle whandle;
    789 
    790    memset(result, 0, sizeof(*result));
    791    result->handle = -1;
    792 
    793    vlsurface = vlGetDataHTAB(surface);
    794    if (!vlsurface || !vlsurface->surface)
    795       return VDP_STATUS_INVALID_HANDLE;
    796 
    797    pipe_mutex_lock(vlsurface->device->mutex);
    798    vlsurface->device->context->flush(vlsurface->device->context, NULL, 0);
    799 
    800    memset(&whandle, 0, sizeof(struct winsys_handle));
    801    whandle.type = DRM_API_HANDLE_TYPE_FD;
    802 
    803    pscreen = vlsurface->surface->texture->screen;
    804    if (!pscreen->resource_get_handle(pscreen, vlsurface->device->context,
    805                                      vlsurface->surface->texture, &whandle,
    806                                      PIPE_HANDLE_USAGE_READ_WRITE)) {
    807       pipe_mutex_unlock(vlsurface->device->mutex);
    808       return VDP_STATUS_NO_IMPLEMENTATION;
    809    }
    810 
    811    pipe_mutex_unlock(vlsurface->device->mutex);
    812 
    813    result->handle = whandle.handle;
    814    result->width = vlsurface->surface->width;
    815    result->height = vlsurface->surface->height;
    816    result->offset = whandle.offset;
    817    result->stride = whandle.stride;
    818    result->format = PipeToFormatRGBA(vlsurface->surface->format);
    819 
    820    return VDP_STATUS_OK;
    821 }
    822