17ec681f3Smrg/**************************************************************************
27ec681f3Smrg *
37ec681f3Smrg * Copyright 2010 Thomas Balling Sørensen.
47ec681f3Smrg * Copyright 2011 Christian König.
57ec681f3Smrg * All Rights Reserved.
67ec681f3Smrg *
77ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87ec681f3Smrg * copy of this software and associated documentation files (the
97ec681f3Smrg * "Software"), to deal in the Software without restriction, including
107ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish,
117ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to
127ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to
137ec681f3Smrg * the following conditions:
147ec681f3Smrg *
157ec681f3Smrg * The above copyright notice and this permission notice (including the
167ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions
177ec681f3Smrg * of the Software.
187ec681f3Smrg *
197ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
207ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
217ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
227ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
237ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
247ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
257ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
267ec681f3Smrg *
277ec681f3Smrg **************************************************************************/
287ec681f3Smrg
297ec681f3Smrg#include <assert.h>
307ec681f3Smrg
317ec681f3Smrg#include "pipe/p_state.h"
327ec681f3Smrg
337ec681f3Smrg#include "util/u_memory.h"
347ec681f3Smrg#include "util/u_debug.h"
357ec681f3Smrg#include "util/u_rect.h"
367ec681f3Smrg#include "util/u_surface.h"
377ec681f3Smrg#include "util/u_video.h"
387ec681f3Smrg#include "vl/vl_defines.h"
397ec681f3Smrg
407ec681f3Smrg#include "frontend/drm_driver.h"
417ec681f3Smrg
427ec681f3Smrg#include "vdpau_private.h"
437ec681f3Smrg
447ec681f3Smrgenum getbits_conversion {
457ec681f3Smrg   CONVERSION_NONE,
467ec681f3Smrg   CONVERSION_NV12_TO_YV12,
477ec681f3Smrg   CONVERSION_YV12_TO_NV12,
487ec681f3Smrg   CONVERSION_SWAP_YUYV_UYVY,
497ec681f3Smrg};
507ec681f3Smrg
517ec681f3Smrg/**
527ec681f3Smrg * Create a VdpVideoSurface.
537ec681f3Smrg */
547ec681f3SmrgVdpStatus
557ec681f3SmrgvlVdpVideoSurfaceCreate(VdpDevice device, VdpChromaType chroma_type,
567ec681f3Smrg                        uint32_t width, uint32_t height,
577ec681f3Smrg                        VdpVideoSurface *surface)
587ec681f3Smrg{
597ec681f3Smrg   struct pipe_context *pipe;
607ec681f3Smrg   vlVdpSurface *p_surf;
617ec681f3Smrg   VdpStatus ret;
627ec681f3Smrg
637ec681f3Smrg   if (!(width && height)) {
647ec681f3Smrg      ret = VDP_STATUS_INVALID_SIZE;
657ec681f3Smrg      goto inv_size;
667ec681f3Smrg   }
677ec681f3Smrg
687ec681f3Smrg   p_surf = CALLOC(1, sizeof(vlVdpSurface));
697ec681f3Smrg   if (!p_surf) {
707ec681f3Smrg      ret = VDP_STATUS_RESOURCES;
717ec681f3Smrg      goto no_res;
727ec681f3Smrg   }
737ec681f3Smrg
747ec681f3Smrg   vlVdpDevice *dev = vlGetDataHTAB(device);
757ec681f3Smrg   if (!dev) {
767ec681f3Smrg      ret = VDP_STATUS_INVALID_HANDLE;
777ec681f3Smrg      goto inv_device;
787ec681f3Smrg   }
797ec681f3Smrg
807ec681f3Smrg   DeviceReference(&p_surf->device, dev);
817ec681f3Smrg   pipe = dev->context;
827ec681f3Smrg
837ec681f3Smrg   mtx_lock(&dev->mutex);
847ec681f3Smrg   memset(&p_surf->templat, 0, sizeof(p_surf->templat));
857ec681f3Smrg   /* TODO: buffer_format should be selected to match chroma_type */
867ec681f3Smrg   p_surf->templat.buffer_format = pipe->screen->get_video_param
877ec681f3Smrg   (
887ec681f3Smrg      pipe->screen,
897ec681f3Smrg      PIPE_VIDEO_PROFILE_UNKNOWN,
907ec681f3Smrg      PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
917ec681f3Smrg      PIPE_VIDEO_CAP_PREFERED_FORMAT
927ec681f3Smrg   );
937ec681f3Smrg   p_surf->templat.width = width;
947ec681f3Smrg   p_surf->templat.height = height;
957ec681f3Smrg   p_surf->templat.interlaced = pipe->screen->get_video_param
967ec681f3Smrg   (
977ec681f3Smrg      pipe->screen,
987ec681f3Smrg      PIPE_VIDEO_PROFILE_UNKNOWN,
997ec681f3Smrg      PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
1007ec681f3Smrg      PIPE_VIDEO_CAP_PREFERS_INTERLACED
1017ec681f3Smrg   );
1027ec681f3Smrg   if (p_surf->templat.buffer_format != PIPE_FORMAT_NONE)
1037ec681f3Smrg      p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
1047ec681f3Smrg
1057ec681f3Smrg   /* do not mandate early allocation of a video buffer */
1067ec681f3Smrg   vlVdpVideoSurfaceClear(p_surf);
1077ec681f3Smrg   mtx_unlock(&dev->mutex);
1087ec681f3Smrg
1097ec681f3Smrg   *surface = vlAddDataHTAB(p_surf);
1107ec681f3Smrg   if (*surface == 0) {
1117ec681f3Smrg      ret = VDP_STATUS_ERROR;
1127ec681f3Smrg      goto no_handle;
1137ec681f3Smrg   }
1147ec681f3Smrg
1157ec681f3Smrg   return VDP_STATUS_OK;
1167ec681f3Smrg
1177ec681f3Smrgno_handle:
1187ec681f3Smrg   p_surf->video_buffer->destroy(p_surf->video_buffer);
1197ec681f3Smrg
1207ec681f3Smrginv_device:
1217ec681f3Smrg   DeviceReference(&p_surf->device, NULL);
1227ec681f3Smrg   FREE(p_surf);
1237ec681f3Smrg
1247ec681f3Smrgno_res:
1257ec681f3Smrginv_size:
1267ec681f3Smrg   return ret;
1277ec681f3Smrg}
1287ec681f3Smrg
1297ec681f3Smrg/**
1307ec681f3Smrg * Destroy a VdpVideoSurface.
1317ec681f3Smrg */
1327ec681f3SmrgVdpStatus
1337ec681f3SmrgvlVdpVideoSurfaceDestroy(VdpVideoSurface surface)
1347ec681f3Smrg{
1357ec681f3Smrg   vlVdpSurface *p_surf;
1367ec681f3Smrg
1377ec681f3Smrg   p_surf = (vlVdpSurface *)vlGetDataHTAB((vlHandle)surface);
1387ec681f3Smrg   if (!p_surf)
1397ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
1407ec681f3Smrg
1417ec681f3Smrg   mtx_lock(&p_surf->device->mutex);
1427ec681f3Smrg   if (p_surf->video_buffer)
1437ec681f3Smrg      p_surf->video_buffer->destroy(p_surf->video_buffer);
1447ec681f3Smrg   mtx_unlock(&p_surf->device->mutex);
1457ec681f3Smrg
1467ec681f3Smrg   vlRemoveDataHTAB(surface);
1477ec681f3Smrg   DeviceReference(&p_surf->device, NULL);
1487ec681f3Smrg   FREE(p_surf);
1497ec681f3Smrg
1507ec681f3Smrg   return VDP_STATUS_OK;
1517ec681f3Smrg}
1527ec681f3Smrg
1537ec681f3Smrg/**
1547ec681f3Smrg * Retrieve the parameters used to create a VdpVideoSurface.
1557ec681f3Smrg */
1567ec681f3SmrgVdpStatus
1577ec681f3SmrgvlVdpVideoSurfaceGetParameters(VdpVideoSurface surface,
1587ec681f3Smrg                               VdpChromaType *chroma_type,
1597ec681f3Smrg                               uint32_t *width, uint32_t *height)
1607ec681f3Smrg{
1617ec681f3Smrg   if (!(width && height && chroma_type))
1627ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
1637ec681f3Smrg
1647ec681f3Smrg   vlVdpSurface *p_surf = vlGetDataHTAB(surface);
1657ec681f3Smrg   if (!p_surf)
1667ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
1677ec681f3Smrg
1687ec681f3Smrg   if (p_surf->video_buffer) {
1697ec681f3Smrg      *width = p_surf->video_buffer->width;
1707ec681f3Smrg      *height = p_surf->video_buffer->height;
1717ec681f3Smrg      *chroma_type = PipeToChroma(pipe_format_to_chroma_format(p_surf->video_buffer->buffer_format));
1727ec681f3Smrg   } else {
1737ec681f3Smrg      *width = p_surf->templat.width;
1747ec681f3Smrg      *height = p_surf->templat.height;
1757ec681f3Smrg      *chroma_type = PipeToChroma(pipe_format_to_chroma_format(p_surf->templat.buffer_format));
1767ec681f3Smrg   }
1777ec681f3Smrg
1787ec681f3Smrg   return VDP_STATUS_OK;
1797ec681f3Smrg}
1807ec681f3Smrg
1817ec681f3Smrgstatic void
1827ec681f3SmrgvlVdpVideoSurfaceSize(vlVdpSurface *p_surf, int component,
1837ec681f3Smrg                      unsigned *width, unsigned *height)
1847ec681f3Smrg{
1857ec681f3Smrg   *width = p_surf->templat.width;
1867ec681f3Smrg   *height = p_surf->templat.height;
1877ec681f3Smrg
1887ec681f3Smrg   vl_video_buffer_adjust_size(width, height, component,
1897ec681f3Smrg                               pipe_format_to_chroma_format(p_surf->templat.buffer_format),
1907ec681f3Smrg                               p_surf->templat.interlaced);
1917ec681f3Smrg}
1927ec681f3Smrg
1937ec681f3Smrg/**
1947ec681f3Smrg * Copy image data from a VdpVideoSurface to application memory in a specified
1957ec681f3Smrg * YCbCr format.
1967ec681f3Smrg */
1977ec681f3SmrgVdpStatus
1987ec681f3SmrgvlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface,
1997ec681f3Smrg                              VdpYCbCrFormat destination_ycbcr_format,
2007ec681f3Smrg                              void *const *destination_data,
2017ec681f3Smrg                              uint32_t const *destination_pitches)
2027ec681f3Smrg{
2037ec681f3Smrg   vlVdpSurface *vlsurface;
2047ec681f3Smrg   struct pipe_context *pipe;
2057ec681f3Smrg   enum pipe_format format, buffer_format;
2067ec681f3Smrg   struct pipe_sampler_view **sampler_views;
2077ec681f3Smrg   enum getbits_conversion conversion = CONVERSION_NONE;
2087ec681f3Smrg   unsigned i, j;
2097ec681f3Smrg
2107ec681f3Smrg   vlsurface = vlGetDataHTAB(surface);
2117ec681f3Smrg   if (!vlsurface)
2127ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
2137ec681f3Smrg
2147ec681f3Smrg   pipe = vlsurface->device->context;
2157ec681f3Smrg   if (!pipe)
2167ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
2177ec681f3Smrg
2187ec681f3Smrg   if (!destination_data || !destination_pitches)
2197ec681f3Smrg       return VDP_STATUS_INVALID_POINTER;
2207ec681f3Smrg
2217ec681f3Smrg   format = FormatYCBCRToPipe(destination_ycbcr_format);
2227ec681f3Smrg   if (format == PIPE_FORMAT_NONE)
2237ec681f3Smrg      return VDP_STATUS_INVALID_Y_CB_CR_FORMAT;
2247ec681f3Smrg
2257ec681f3Smrg   if (vlsurface->video_buffer == NULL)
2267ec681f3Smrg      return VDP_STATUS_INVALID_VALUE;
2277ec681f3Smrg
2287ec681f3Smrg   buffer_format = vlsurface->video_buffer->buffer_format;
2297ec681f3Smrg   if (format != buffer_format) {
2307ec681f3Smrg      if (format == PIPE_FORMAT_YV12 && buffer_format == PIPE_FORMAT_NV12)
2317ec681f3Smrg         conversion = CONVERSION_NV12_TO_YV12;
2327ec681f3Smrg      else if (format == PIPE_FORMAT_NV12 && buffer_format == PIPE_FORMAT_YV12)
2337ec681f3Smrg         conversion = CONVERSION_YV12_TO_NV12;
2347ec681f3Smrg      else if ((format == PIPE_FORMAT_YUYV && buffer_format == PIPE_FORMAT_UYVY) ||
2357ec681f3Smrg               (format == PIPE_FORMAT_UYVY && buffer_format == PIPE_FORMAT_YUYV))
2367ec681f3Smrg         conversion = CONVERSION_SWAP_YUYV_UYVY;
2377ec681f3Smrg      else
2387ec681f3Smrg         return VDP_STATUS_NO_IMPLEMENTATION;
2397ec681f3Smrg   }
2407ec681f3Smrg
2417ec681f3Smrg   mtx_lock(&vlsurface->device->mutex);
2427ec681f3Smrg   sampler_views = vlsurface->video_buffer->get_sampler_view_planes(vlsurface->video_buffer);
2437ec681f3Smrg   if (!sampler_views) {
2447ec681f3Smrg      mtx_unlock(&vlsurface->device->mutex);
2457ec681f3Smrg      return VDP_STATUS_RESOURCES;
2467ec681f3Smrg   }
2477ec681f3Smrg
2487ec681f3Smrg   for (i = 0; i < 3; ++i) {
2497ec681f3Smrg      unsigned width, height;
2507ec681f3Smrg      struct pipe_sampler_view *sv = sampler_views[i];
2517ec681f3Smrg      if (!sv) continue;
2527ec681f3Smrg
2537ec681f3Smrg      vlVdpVideoSurfaceSize(vlsurface, i, &width, &height);
2547ec681f3Smrg
2557ec681f3Smrg      for (j = 0; j < sv->texture->array_size; ++j) {
2567ec681f3Smrg         struct pipe_box box = {
2577ec681f3Smrg            0, 0, j,
2587ec681f3Smrg            width, height, 1
2597ec681f3Smrg         };
2607ec681f3Smrg         struct pipe_transfer *transfer;
2617ec681f3Smrg         uint8_t *map;
2627ec681f3Smrg
2637ec681f3Smrg         map = pipe->texture_map(pipe, sv->texture, 0,
2647ec681f3Smrg                                       PIPE_MAP_READ, &box, &transfer);
2657ec681f3Smrg         if (!map) {
2667ec681f3Smrg            mtx_unlock(&vlsurface->device->mutex);
2677ec681f3Smrg            return VDP_STATUS_RESOURCES;
2687ec681f3Smrg         }
2697ec681f3Smrg
2707ec681f3Smrg         if (conversion == CONVERSION_NV12_TO_YV12 && i == 1) {
2717ec681f3Smrg            u_copy_nv12_to_yv12(destination_data, destination_pitches,
2727ec681f3Smrg                                i, j, transfer->stride, sv->texture->array_size,
2737ec681f3Smrg                                map, box.width, box.height);
2747ec681f3Smrg         } else if (conversion == CONVERSION_YV12_TO_NV12 && i > 0) {
2757ec681f3Smrg            u_copy_yv12_to_nv12(destination_data, destination_pitches,
2767ec681f3Smrg                                i, j, transfer->stride, sv->texture->array_size,
2777ec681f3Smrg                                map, box.width, box.height);
2787ec681f3Smrg         } else if (conversion == CONVERSION_SWAP_YUYV_UYVY) {
2797ec681f3Smrg            u_copy_swap422_packed(destination_data, destination_pitches,
2807ec681f3Smrg                                   i, j, transfer->stride, sv->texture->array_size,
2817ec681f3Smrg                                   map, box.width, box.height);
2827ec681f3Smrg         } else {
2837ec681f3Smrg            util_copy_rect(destination_data[i] + destination_pitches[i] * j, sv->texture->format,
2847ec681f3Smrg                           destination_pitches[i] * sv->texture->array_size, 0, 0,
2857ec681f3Smrg                           box.width, box.height, map, transfer->stride, 0, 0);
2867ec681f3Smrg         }
2877ec681f3Smrg
2887ec681f3Smrg         pipe_texture_unmap(pipe, transfer);
2897ec681f3Smrg      }
2907ec681f3Smrg   }
2917ec681f3Smrg   mtx_unlock(&vlsurface->device->mutex);
2927ec681f3Smrg
2937ec681f3Smrg   return VDP_STATUS_OK;
2947ec681f3Smrg}
2957ec681f3Smrg
2967ec681f3Smrg/**
2977ec681f3Smrg * Copy image data from application memory in a specific YCbCr format to
2987ec681f3Smrg * a VdpVideoSurface.
2997ec681f3Smrg */
3007ec681f3SmrgVdpStatus
3017ec681f3SmrgvlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,
3027ec681f3Smrg                              VdpYCbCrFormat source_ycbcr_format,
3037ec681f3Smrg                              void const *const *source_data,
3047ec681f3Smrg                              uint32_t const *source_pitches)
3057ec681f3Smrg{
3067ec681f3Smrg   enum pipe_format pformat = FormatYCBCRToPipe(source_ycbcr_format);
3077ec681f3Smrg   enum getbits_conversion conversion = CONVERSION_NONE;
3087ec681f3Smrg   struct pipe_context *pipe;
3097ec681f3Smrg   struct pipe_sampler_view **sampler_views;
3107ec681f3Smrg   unsigned i, j;
3117ec681f3Smrg   unsigned usage = PIPE_MAP_WRITE;
3127ec681f3Smrg
3137ec681f3Smrg   vlVdpSurface *p_surf = vlGetDataHTAB(surface);
3147ec681f3Smrg   if (!p_surf)
3157ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
3167ec681f3Smrg
3177ec681f3Smrg   pipe = p_surf->device->context;
3187ec681f3Smrg   if (!pipe)
3197ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
3207ec681f3Smrg
3217ec681f3Smrg   if (!source_data || !source_pitches)
3227ec681f3Smrg       return VDP_STATUS_INVALID_POINTER;
3237ec681f3Smrg
3247ec681f3Smrg   mtx_lock(&p_surf->device->mutex);
3257ec681f3Smrg
3267ec681f3Smrg   if (p_surf->video_buffer == NULL ||
3277ec681f3Smrg       ((pformat != p_surf->video_buffer->buffer_format))) {
3287ec681f3Smrg      enum pipe_format nformat = pformat;
3297ec681f3Smrg      struct pipe_screen *screen = pipe->screen;
3307ec681f3Smrg
3317ec681f3Smrg      /* Determine the most suitable format for the new surface */
3327ec681f3Smrg      if (!screen->is_video_format_supported(screen, nformat,
3337ec681f3Smrg                                             PIPE_VIDEO_PROFILE_UNKNOWN,
3347ec681f3Smrg                                             PIPE_VIDEO_ENTRYPOINT_BITSTREAM)) {
3357ec681f3Smrg         nformat = screen->get_video_param(screen,
3367ec681f3Smrg                                           PIPE_VIDEO_PROFILE_UNKNOWN,
3377ec681f3Smrg                                           PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
3387ec681f3Smrg                                           PIPE_VIDEO_CAP_PREFERED_FORMAT);
3397ec681f3Smrg         if (nformat == PIPE_FORMAT_NONE) {
3407ec681f3Smrg            mtx_unlock(&p_surf->device->mutex);
3417ec681f3Smrg            return VDP_STATUS_NO_IMPLEMENTATION;
3427ec681f3Smrg         }
3437ec681f3Smrg      }
3447ec681f3Smrg
3457ec681f3Smrg      if (p_surf->video_buffer == NULL  ||
3467ec681f3Smrg          nformat != p_surf->video_buffer->buffer_format) {
3477ec681f3Smrg         /* destroy the old one */
3487ec681f3Smrg         if (p_surf->video_buffer)
3497ec681f3Smrg            p_surf->video_buffer->destroy(p_surf->video_buffer);
3507ec681f3Smrg
3517ec681f3Smrg         /* adjust the template parameters */
3527ec681f3Smrg         p_surf->templat.buffer_format = nformat;
3537ec681f3Smrg         if (nformat == PIPE_FORMAT_YUYV || nformat == PIPE_FORMAT_UYVY)
3547ec681f3Smrg            p_surf->templat.interlaced = false;
3557ec681f3Smrg
3567ec681f3Smrg         /* and try to create the video buffer with the new format */
3577ec681f3Smrg         p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
3587ec681f3Smrg
3597ec681f3Smrg         /* stil no luck? ok forget it we don't support it */
3607ec681f3Smrg         if (!p_surf->video_buffer) {
3617ec681f3Smrg            mtx_unlock(&p_surf->device->mutex);
3627ec681f3Smrg            return VDP_STATUS_NO_IMPLEMENTATION;
3637ec681f3Smrg         }
3647ec681f3Smrg         vlVdpVideoSurfaceClear(p_surf);
3657ec681f3Smrg      }
3667ec681f3Smrg   }
3677ec681f3Smrg
3687ec681f3Smrg   if (pformat != p_surf->video_buffer->buffer_format) {
3697ec681f3Smrg      if (pformat == PIPE_FORMAT_YV12 &&
3707ec681f3Smrg          p_surf->video_buffer->buffer_format == PIPE_FORMAT_NV12)
3717ec681f3Smrg         conversion = CONVERSION_YV12_TO_NV12;
3727ec681f3Smrg      else {
3737ec681f3Smrg         mtx_unlock(&p_surf->device->mutex);
3747ec681f3Smrg         return VDP_STATUS_NO_IMPLEMENTATION;
3757ec681f3Smrg      }
3767ec681f3Smrg   }
3777ec681f3Smrg
3787ec681f3Smrg   sampler_views = p_surf->video_buffer->get_sampler_view_planes(p_surf->video_buffer);
3797ec681f3Smrg   if (!sampler_views) {
3807ec681f3Smrg      mtx_unlock(&p_surf->device->mutex);
3817ec681f3Smrg      return VDP_STATUS_RESOURCES;
3827ec681f3Smrg   }
3837ec681f3Smrg
3847ec681f3Smrg   for (i = 0; i < 3; ++i) {
3857ec681f3Smrg      unsigned width, height;
3867ec681f3Smrg      struct pipe_sampler_view *sv = sampler_views[i];
3877ec681f3Smrg      struct pipe_resource *tex;
3887ec681f3Smrg      if (!sv || !source_pitches[i]) continue;
3897ec681f3Smrg
3907ec681f3Smrg      tex = sv->texture;
3917ec681f3Smrg      vlVdpVideoSurfaceSize(p_surf, i, &width, &height);
3927ec681f3Smrg
3937ec681f3Smrg      for (j = 0; j < tex->array_size; ++j) {
3947ec681f3Smrg         struct pipe_box dst_box = {
3957ec681f3Smrg            0, 0, j,
3967ec681f3Smrg            width, height, 1
3977ec681f3Smrg         };
3987ec681f3Smrg
3997ec681f3Smrg         if (conversion == CONVERSION_YV12_TO_NV12 && i == 1) {
4007ec681f3Smrg            struct pipe_transfer *transfer;
4017ec681f3Smrg            uint8_t *map;
4027ec681f3Smrg
4037ec681f3Smrg            map = pipe->texture_map(pipe, tex, 0, usage,
4047ec681f3Smrg                                     &dst_box, &transfer);
4057ec681f3Smrg            if (!map) {
4067ec681f3Smrg               mtx_unlock(&p_surf->device->mutex);
4077ec681f3Smrg               return VDP_STATUS_RESOURCES;
4087ec681f3Smrg            }
4097ec681f3Smrg
4107ec681f3Smrg            u_copy_nv12_from_yv12(source_data, source_pitches,
4117ec681f3Smrg                                  i, j, transfer->stride, tex->array_size,
4127ec681f3Smrg                                  map, dst_box.width, dst_box.height);
4137ec681f3Smrg
4147ec681f3Smrg            pipe_texture_unmap(pipe, transfer);
4157ec681f3Smrg         } else {
4167ec681f3Smrg            pipe->texture_subdata(pipe, tex, 0,
4177ec681f3Smrg                                  PIPE_MAP_WRITE, &dst_box,
4187ec681f3Smrg                                  source_data[i] + source_pitches[i] * j,
4197ec681f3Smrg                                  source_pitches[i] * tex->array_size,
4207ec681f3Smrg                                  0);
4217ec681f3Smrg         }
4227ec681f3Smrg         /*
4237ec681f3Smrg          * This surface has already been synced
4247ec681f3Smrg          * by the first map.
4257ec681f3Smrg          */
4267ec681f3Smrg         usage |= PIPE_MAP_UNSYNCHRONIZED;
4277ec681f3Smrg      }
4287ec681f3Smrg   }
4297ec681f3Smrg   mtx_unlock(&p_surf->device->mutex);
4307ec681f3Smrg
4317ec681f3Smrg   return VDP_STATUS_OK;
4327ec681f3Smrg}
4337ec681f3Smrg
4347ec681f3Smrg/**
4357ec681f3Smrg * Helper function to initially clear the VideoSurface after (re-)creation
4367ec681f3Smrg */
4377ec681f3Smrgvoid
4387ec681f3SmrgvlVdpVideoSurfaceClear(vlVdpSurface *vlsurf)
4397ec681f3Smrg{
4407ec681f3Smrg   struct pipe_context *pipe = vlsurf->device->context;
4417ec681f3Smrg   struct pipe_surface **surfaces;
4427ec681f3Smrg   unsigned i;
4437ec681f3Smrg
4447ec681f3Smrg   if (!vlsurf->video_buffer)
4457ec681f3Smrg      return;
4467ec681f3Smrg
4477ec681f3Smrg   surfaces = vlsurf->video_buffer->get_surfaces(vlsurf->video_buffer);
4487ec681f3Smrg   for (i = 0; i < VL_MAX_SURFACES; ++i) {
4497ec681f3Smrg      union pipe_color_union c = {};
4507ec681f3Smrg
4517ec681f3Smrg      if (!surfaces[i])
4527ec681f3Smrg         continue;
4537ec681f3Smrg
4547ec681f3Smrg      if (i > !!vlsurf->templat.interlaced)
4557ec681f3Smrg         c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f;
4567ec681f3Smrg
4577ec681f3Smrg      pipe->clear_render_target(pipe, surfaces[i], &c, 0, 0,
4587ec681f3Smrg                                surfaces[i]->width, surfaces[i]->height, false);
4597ec681f3Smrg   }
4607ec681f3Smrg   pipe->flush(pipe, NULL, 0);
4617ec681f3Smrg}
4627ec681f3Smrg
4637ec681f3Smrg/**
4647ec681f3Smrg * Interop for the GL gallium frontend
4657ec681f3Smrg */
4667ec681f3Smrgstruct pipe_video_buffer *vlVdpVideoSurfaceGallium(VdpVideoSurface surface)
4677ec681f3Smrg{
4687ec681f3Smrg   vlVdpSurface *p_surf = vlGetDataHTAB(surface);
4697ec681f3Smrg   if (!p_surf)
4707ec681f3Smrg      return NULL;
4717ec681f3Smrg
4727ec681f3Smrg   mtx_lock(&p_surf->device->mutex);
4737ec681f3Smrg   if (p_surf->video_buffer == NULL) {
4747ec681f3Smrg      struct pipe_context *pipe = p_surf->device->context;
4757ec681f3Smrg
4767ec681f3Smrg      /* try to create a video buffer if we don't already have one */
4777ec681f3Smrg      p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
4787ec681f3Smrg   }
4797ec681f3Smrg   mtx_unlock(&p_surf->device->mutex);
4807ec681f3Smrg
4817ec681f3Smrg   return p_surf->video_buffer;
4827ec681f3Smrg}
4837ec681f3Smrg
4847ec681f3SmrgVdpStatus vlVdpVideoSurfaceDMABuf(VdpVideoSurface surface,
4857ec681f3Smrg                                  VdpVideoSurfacePlane plane,
4867ec681f3Smrg                                  struct VdpSurfaceDMABufDesc *result)
4877ec681f3Smrg{
4887ec681f3Smrg   vlVdpSurface *p_surf = vlGetDataHTAB(surface);
4897ec681f3Smrg
4907ec681f3Smrg   struct pipe_screen *pscreen;
4917ec681f3Smrg   struct winsys_handle whandle;
4927ec681f3Smrg
4937ec681f3Smrg   struct pipe_surface *surf;
4947ec681f3Smrg
4957ec681f3Smrg   if (!p_surf)
4967ec681f3Smrg      return VDP_STATUS_INVALID_HANDLE;
4977ec681f3Smrg
4987ec681f3Smrg   if (plane > 3)
4997ec681f3Smrg      return VDP_STATUS_INVALID_VALUE;
5007ec681f3Smrg
5017ec681f3Smrg   if (!result)
5027ec681f3Smrg      return VDP_STATUS_INVALID_POINTER;
5037ec681f3Smrg
5047ec681f3Smrg   memset(result, 0, sizeof(*result));
5057ec681f3Smrg   result->handle = -1;
5067ec681f3Smrg
5077ec681f3Smrg   mtx_lock(&p_surf->device->mutex);
5087ec681f3Smrg   if (p_surf->video_buffer == NULL) {
5097ec681f3Smrg      struct pipe_context *pipe = p_surf->device->context;
5107ec681f3Smrg
5117ec681f3Smrg      /* try to create a video buffer if we don't already have one */
5127ec681f3Smrg      p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
5137ec681f3Smrg   }
5147ec681f3Smrg
5157ec681f3Smrg   /* Check if surface match interop requirements */
5167ec681f3Smrg   if (p_surf->video_buffer == NULL || !p_surf->video_buffer->interlaced ||
5177ec681f3Smrg       p_surf->video_buffer->buffer_format != PIPE_FORMAT_NV12) {
5187ec681f3Smrg      mtx_unlock(&p_surf->device->mutex);
5197ec681f3Smrg      return VDP_STATUS_NO_IMPLEMENTATION;
5207ec681f3Smrg   }
5217ec681f3Smrg
5227ec681f3Smrg   surf = p_surf->video_buffer->get_surfaces(p_surf->video_buffer)[plane];
5237ec681f3Smrg   if (!surf) {
5247ec681f3Smrg      mtx_unlock(&p_surf->device->mutex);
5257ec681f3Smrg      return VDP_STATUS_RESOURCES;
5267ec681f3Smrg   }
5277ec681f3Smrg
5287ec681f3Smrg   memset(&whandle, 0, sizeof(struct winsys_handle));
5297ec681f3Smrg   whandle.type = WINSYS_HANDLE_TYPE_FD;
5307ec681f3Smrg   whandle.layer = surf->u.tex.first_layer;
5317ec681f3Smrg
5327ec681f3Smrg   pscreen = surf->texture->screen;
5337ec681f3Smrg   if (!pscreen->resource_get_handle(pscreen, p_surf->device->context,
5347ec681f3Smrg                                     surf->texture, &whandle,
5357ec681f3Smrg                                     PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)) {
5367ec681f3Smrg      mtx_unlock(&p_surf->device->mutex);
5377ec681f3Smrg      return VDP_STATUS_NO_IMPLEMENTATION;
5387ec681f3Smrg   }
5397ec681f3Smrg
5407ec681f3Smrg   mtx_unlock(&p_surf->device->mutex);
5417ec681f3Smrg
5427ec681f3Smrg   result->handle = whandle.handle;
5437ec681f3Smrg   result->width = surf->width;
5447ec681f3Smrg   result->height = surf->height;
5457ec681f3Smrg   result->offset = whandle.offset;
5467ec681f3Smrg   result->stride = whandle.stride;
5477ec681f3Smrg
5487ec681f3Smrg   if (surf->format == PIPE_FORMAT_R8_UNORM)
5497ec681f3Smrg      result->format = VDP_RGBA_FORMAT_R8;
5507ec681f3Smrg   else
5517ec681f3Smrg      result->format = VDP_RGBA_FORMAT_R8G8;
5527ec681f3Smrg
5537ec681f3Smrg   return VDP_STATUS_OK;
5547ec681f3Smrg}
555