1af69d88dSmrg/**************************************************************************
2af69d88dSmrg *
3af69d88dSmrg * Copyright 2013 Advanced Micro Devices, Inc.
4af69d88dSmrg * All Rights Reserved.
5af69d88dSmrg *
6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
7af69d88dSmrg * copy of this software and associated documentation files (the
8af69d88dSmrg * "Software"), to deal in the Software without restriction, including
9af69d88dSmrg * without limitation the rights to use, copy, modify, merge, publish,
10af69d88dSmrg * distribute, sub license, and/or sell copies of the Software, and to
11af69d88dSmrg * permit persons to whom the Software is furnished to do so, subject to
12af69d88dSmrg * the following conditions:
13af69d88dSmrg *
14af69d88dSmrg * The above copyright notice and this permission notice (including the
15af69d88dSmrg * next paragraph) shall be included in all copies or substantial portions
16af69d88dSmrg * of the Software.
17af69d88dSmrg *
18af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20af69d88dSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21af69d88dSmrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
22af69d88dSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23af69d88dSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24af69d88dSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25af69d88dSmrg *
26af69d88dSmrg **************************************************************************/
27af69d88dSmrg
28af69d88dSmrg/*
29af69d88dSmrg * Authors:
30af69d88dSmrg *      Christian König <christian.koenig@amd.com>
31af69d88dSmrg *
32af69d88dSmrg */
33af69d88dSmrg
3401e04c3fSmrg#ifdef HAVE_ST_VDPAU
3501e04c3fSmrg
36af69d88dSmrg#include "main/texobj.h"
37af69d88dSmrg#include "main/teximage.h"
38af69d88dSmrg#include "main/errors.h"
39af69d88dSmrg#include "program/prog_instruction.h"
40af69d88dSmrg
41af69d88dSmrg#include "pipe/p_state.h"
42af69d88dSmrg#include "pipe/p_video_codec.h"
43af69d88dSmrg
44af69d88dSmrg#include "util/u_inlines.h"
45af69d88dSmrg
46af69d88dSmrg#include "st_vdpau.h"
47af69d88dSmrg#include "st_context.h"
4801e04c3fSmrg#include "st_sampler_view.h"
49af69d88dSmrg#include "st_texture.h"
50af69d88dSmrg#include "st_format.h"
51af69d88dSmrg#include "st_cb_flush.h"
52af69d88dSmrg
537ec681f3Smrg#include "frontend/vdpau_interop.h"
547ec681f3Smrg#include "frontend/vdpau_dmabuf.h"
557ec681f3Smrg#include "frontend/vdpau_funcs.h"
567ec681f3Smrg#include "frontend/drm_driver.h"
577ec681f3Smrg
587ec681f3Smrg#include "drm-uapi/drm_fourcc.h"
5901e04c3fSmrg
6001e04c3fSmrgstatic struct pipe_resource *
6101e04c3fSmrgst_vdpau_video_surface_gallium(struct gl_context *ctx, const void *vdpSurface,
6201e04c3fSmrg                               GLuint index)
6301e04c3fSmrg{
6401e04c3fSmrg   int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr);
6501e04c3fSmrg   uint32_t device = (uintptr_t)ctx->vdpDevice;
6601e04c3fSmrg   struct pipe_sampler_view *sv;
6701e04c3fSmrg   VdpVideoSurfaceGallium *f;
6801e04c3fSmrg
6901e04c3fSmrg   struct pipe_video_buffer *buffer;
7001e04c3fSmrg   struct pipe_sampler_view **samplers;
7101e04c3fSmrg   struct pipe_resource *res = NULL;
7201e04c3fSmrg
7301e04c3fSmrg   getProcAddr = (void *)ctx->vdpGetProcAddress;
7401e04c3fSmrg   if (getProcAddr(device, VDP_FUNC_ID_VIDEO_SURFACE_GALLIUM, (void**)&f))
7501e04c3fSmrg      return NULL;
7601e04c3fSmrg
7701e04c3fSmrg   buffer = f((uintptr_t)vdpSurface);
7801e04c3fSmrg   if (!buffer)
7901e04c3fSmrg      return NULL;
8001e04c3fSmrg
8101e04c3fSmrg   samplers = buffer->get_sampler_view_planes(buffer);
8201e04c3fSmrg   if (!samplers)
8301e04c3fSmrg      return NULL;
8401e04c3fSmrg
8501e04c3fSmrg   sv = samplers[index >> 1];
8601e04c3fSmrg   if (!sv)
8701e04c3fSmrg      return NULL;
8801e04c3fSmrg
8901e04c3fSmrg   pipe_resource_reference(&res, sv->texture);
9001e04c3fSmrg   return res;
9101e04c3fSmrg}
9201e04c3fSmrg
9301e04c3fSmrgstatic struct pipe_resource *
9401e04c3fSmrgst_vdpau_output_surface_gallium(struct gl_context *ctx, const void *vdpSurface)
9501e04c3fSmrg{
9601e04c3fSmrg   int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr);
9701e04c3fSmrg   uint32_t device = (uintptr_t)ctx->vdpDevice;
9801e04c3fSmrg   struct pipe_resource *res = NULL;
9901e04c3fSmrg   VdpOutputSurfaceGallium *f;
10001e04c3fSmrg
10101e04c3fSmrg   getProcAddr = (void *)ctx->vdpGetProcAddress;
10201e04c3fSmrg   if (getProcAddr(device, VDP_FUNC_ID_OUTPUT_SURFACE_GALLIUM, (void**)&f))
10301e04c3fSmrg      return NULL;
10401e04c3fSmrg
10501e04c3fSmrg   pipe_resource_reference(&res, f((uintptr_t)vdpSurface));
10601e04c3fSmrg   return res;
10701e04c3fSmrg}
10801e04c3fSmrg
10901e04c3fSmrgstatic struct pipe_resource *
11001e04c3fSmrgst_vdpau_resource_from_description(struct gl_context *ctx,
11101e04c3fSmrg                                   const struct VdpSurfaceDMABufDesc *desc)
11201e04c3fSmrg{
11301e04c3fSmrg   struct st_context *st = st_context(ctx);
11401e04c3fSmrg   struct pipe_resource templ, *res;
11501e04c3fSmrg   struct winsys_handle whandle;
11601e04c3fSmrg
11701e04c3fSmrg   if (desc->handle == -1)
11801e04c3fSmrg      return NULL;
11901e04c3fSmrg
12001e04c3fSmrg   memset(&templ, 0, sizeof(templ));
12101e04c3fSmrg   templ.target = PIPE_TEXTURE_2D;
12201e04c3fSmrg   templ.last_level = 0;
12301e04c3fSmrg   templ.depth0 = 1;
12401e04c3fSmrg   templ.array_size = 1;
12501e04c3fSmrg   templ.width0 = desc->width;
12601e04c3fSmrg   templ.height0 = desc->height;
12701e04c3fSmrg   templ.format = VdpFormatRGBAToPipe(desc->format);
12801e04c3fSmrg   templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
12901e04c3fSmrg   templ.usage = PIPE_USAGE_DEFAULT;
13001e04c3fSmrg
13101e04c3fSmrg   memset(&whandle, 0, sizeof(whandle));
13201e04c3fSmrg   whandle.type = WINSYS_HANDLE_TYPE_FD;
13301e04c3fSmrg   whandle.handle = desc->handle;
1347ec681f3Smrg   whandle.modifier = DRM_FORMAT_MOD_INVALID;
13501e04c3fSmrg   whandle.offset = desc->offset;
13601e04c3fSmrg   whandle.stride = desc->stride;
13701e04c3fSmrg
1387ec681f3Smrg   res = st->screen->resource_from_handle(st->screen, &templ, &whandle,
1397ec681f3Smrg                                          PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
14001e04c3fSmrg   close(desc->handle);
14101e04c3fSmrg
14201e04c3fSmrg   return res;
14301e04c3fSmrg}
14401e04c3fSmrg
14501e04c3fSmrgstatic struct pipe_resource *
14601e04c3fSmrgst_vdpau_output_surface_dma_buf(struct gl_context *ctx, const void *vdpSurface)
14701e04c3fSmrg{
14801e04c3fSmrg   int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr);
14901e04c3fSmrg   uint32_t device = (uintptr_t)ctx->vdpDevice;
15001e04c3fSmrg
15101e04c3fSmrg   struct VdpSurfaceDMABufDesc desc;
15201e04c3fSmrg   VdpOutputSurfaceDMABuf *f;
15301e04c3fSmrg
15401e04c3fSmrg   getProcAddr = (void *)ctx->vdpGetProcAddress;
15501e04c3fSmrg   if (getProcAddr(device, VDP_FUNC_ID_OUTPUT_SURFACE_DMA_BUF, (void**)&f))
15601e04c3fSmrg      return NULL;
15701e04c3fSmrg
15801e04c3fSmrg   if (f((uintptr_t)vdpSurface, &desc) != VDP_STATUS_OK)
15901e04c3fSmrg      return NULL;
16001e04c3fSmrg
16101e04c3fSmrg   return st_vdpau_resource_from_description(ctx, &desc);
16201e04c3fSmrg}
16301e04c3fSmrg
16401e04c3fSmrgstatic struct pipe_resource *
16501e04c3fSmrgst_vdpau_video_surface_dma_buf(struct gl_context *ctx, const void *vdpSurface,
16601e04c3fSmrg                               GLuint index)
16701e04c3fSmrg{
16801e04c3fSmrg   int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr);
16901e04c3fSmrg   uint32_t device = (uintptr_t)ctx->vdpDevice;
17001e04c3fSmrg
17101e04c3fSmrg   struct VdpSurfaceDMABufDesc desc;
17201e04c3fSmrg   VdpVideoSurfaceDMABuf *f;
17301e04c3fSmrg
17401e04c3fSmrg   getProcAddr = (void *)ctx->vdpGetProcAddress;
17501e04c3fSmrg   if (getProcAddr(device, VDP_FUNC_ID_VIDEO_SURFACE_DMA_BUF, (void**)&f))
17601e04c3fSmrg      return NULL;
17701e04c3fSmrg
17801e04c3fSmrg   if (f((uintptr_t)vdpSurface, index, &desc) != VDP_STATUS_OK)
17901e04c3fSmrg      return NULL;
18001e04c3fSmrg
18101e04c3fSmrg   return st_vdpau_resource_from_description(ctx, &desc);
18201e04c3fSmrg}
18301e04c3fSmrg
184af69d88dSmrgstatic void
185af69d88dSmrgst_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access,
186af69d88dSmrg                     GLboolean output, struct gl_texture_object *texObj,
187af69d88dSmrg                     struct gl_texture_image *texImage,
18801e04c3fSmrg                     const void *vdpSurface, GLuint index)
189af69d88dSmrg{
190af69d88dSmrg   struct st_context *st = st_context(ctx);
1917ec681f3Smrg   struct pipe_screen *screen = st->screen;
192af69d88dSmrg   struct st_texture_object *stObj = st_texture_object(texObj);
193af69d88dSmrg   struct st_texture_image *stImage = st_texture_image(texImage);
19401e04c3fSmrg
195af69d88dSmrg   struct pipe_resource *res;
196af69d88dSmrg   mesa_format texFormat;
1977ec681f3Smrg   int layer_override = -1;
198af69d88dSmrg
199af69d88dSmrg   if (output) {
20001e04c3fSmrg      res = st_vdpau_output_surface_dma_buf(ctx, vdpSurface);
201af69d88dSmrg
20201e04c3fSmrg      if (!res)
20301e04c3fSmrg         res = st_vdpau_output_surface_gallium(ctx, vdpSurface);
204af69d88dSmrg
205af69d88dSmrg   } else {
20601e04c3fSmrg      res = st_vdpau_video_surface_dma_buf(ctx, vdpSurface, index);
207af69d88dSmrg
20801e04c3fSmrg      if (!res) {
20901e04c3fSmrg         res = st_vdpau_video_surface_gallium(ctx, vdpSurface, index);
21001e04c3fSmrg         layer_override = index & 1;
211af69d88dSmrg      }
212af69d88dSmrg   }
213af69d88dSmrg
2147ec681f3Smrg   /* If the resource is from a different screen, try re-importing it */
2157ec681f3Smrg   if (res && res->screen != screen) {
2167ec681f3Smrg      struct pipe_resource *new_res = NULL;
2177ec681f3Smrg      struct winsys_handle whandle = { .type = WINSYS_HANDLE_TYPE_FD };
2187ec681f3Smrg      unsigned usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
2197ec681f3Smrg
2207ec681f3Smrg      if (screen->get_param(screen, PIPE_CAP_DMABUF) &&
2217ec681f3Smrg          res->screen->get_param(res->screen, PIPE_CAP_DMABUF) &&
2227ec681f3Smrg          res->screen->resource_get_handle(res->screen, NULL, res, &whandle,
2237ec681f3Smrg                                           usage)) {
2247ec681f3Smrg         whandle.modifier = DRM_FORMAT_MOD_INVALID;
2257ec681f3Smrg         new_res = screen->resource_from_handle(screen, res, &whandle, usage);
2267ec681f3Smrg         close(whandle.handle);
2277ec681f3Smrg      }
2287ec681f3Smrg
2297ec681f3Smrg      pipe_resource_reference(&res, NULL);
2307ec681f3Smrg      res = new_res;
231af69d88dSmrg   }
232af69d88dSmrg
2337ec681f3Smrg   if (!res) {
234af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV");
235af69d88dSmrg      return;
236af69d88dSmrg   }
237af69d88dSmrg
238af69d88dSmrg   /* switch to surface based */
239af69d88dSmrg   if (!stObj->surface_based) {
24001e04c3fSmrg      _mesa_clear_texture_object(ctx, texObj, NULL);
241af69d88dSmrg      stObj->surface_based = GL_TRUE;
242af69d88dSmrg   }
243af69d88dSmrg
244af69d88dSmrg   texFormat = st_pipe_format_to_mesa_format(res->format);
245af69d88dSmrg
246af69d88dSmrg   _mesa_init_teximage_fields(ctx, texImage,
247af69d88dSmrg                              res->width0, res->height0, 1, 0, GL_RGBA,
248af69d88dSmrg                              texFormat);
249af69d88dSmrg
250af69d88dSmrg   pipe_resource_reference(&stObj->pt, res);
251af69d88dSmrg   st_texture_release_all_sampler_views(st, stObj);
252af69d88dSmrg   pipe_resource_reference(&stImage->pt, res);
253af69d88dSmrg
254af69d88dSmrg   stObj->surface_format = res->format;
2557ec681f3Smrg   stObj->level_override = -1;
25601e04c3fSmrg   stObj->layer_override = layer_override;
257af69d88dSmrg
258af69d88dSmrg   _mesa_dirty_texobj(ctx, texObj);
25901e04c3fSmrg   pipe_resource_reference(&res, NULL);
260af69d88dSmrg}
261af69d88dSmrg
262af69d88dSmrgstatic void
263af69d88dSmrgst_vdpau_unmap_surface(struct gl_context *ctx, GLenum target, GLenum access,
264af69d88dSmrg                       GLboolean output, struct gl_texture_object *texObj,
265af69d88dSmrg                       struct gl_texture_image *texImage,
26601e04c3fSmrg                       const void *vdpSurface, GLuint index)
267af69d88dSmrg{
268af69d88dSmrg   struct st_context *st = st_context(ctx);
269af69d88dSmrg   struct st_texture_object *stObj = st_texture_object(texObj);
270af69d88dSmrg   struct st_texture_image *stImage = st_texture_image(texImage);
271af69d88dSmrg
272af69d88dSmrg   pipe_resource_reference(&stObj->pt, NULL);
273af69d88dSmrg   st_texture_release_all_sampler_views(st, stObj);
274af69d88dSmrg   pipe_resource_reference(&stImage->pt, NULL);
275af69d88dSmrg
2767ec681f3Smrg   stObj->level_override = -1;
2777ec681f3Smrg   stObj->layer_override = -1;
27801e04c3fSmrg
279af69d88dSmrg   _mesa_dirty_texobj(ctx, texObj);
280af69d88dSmrg
28101e04c3fSmrg   /* NV_vdpau_interop does not specify an explicit synchronization mechanism
28201e04c3fSmrg    * between the GL and VDPAU contexts. Provide automatic synchronization here.
28301e04c3fSmrg    */
284af69d88dSmrg   st_flush(st, NULL, 0);
285af69d88dSmrg}
286af69d88dSmrg
287af69d88dSmrgvoid
288af69d88dSmrgst_init_vdpau_functions(struct dd_function_table *functions)
289af69d88dSmrg{
290af69d88dSmrg   functions->VDPAUMapSurface = st_vdpau_map_surface;
291af69d88dSmrg   functions->VDPAUUnmapSurface = st_vdpau_unmap_surface;
292af69d88dSmrg}
29301e04c3fSmrg#endif
294