1 /************************************************************************** 2 * 3 * Copyright 2013 Advanced Micro Devices, Inc. 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 THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 /* 29 * Authors: 30 * Christian Knig <christian.koenig (at) amd.com> 31 * 32 */ 33 34 #ifdef HAVE_ST_VDPAU 35 36 #include "main/texobj.h" 37 #include "main/teximage.h" 38 #include "main/errors.h" 39 #include "program/prog_instruction.h" 40 41 #include "pipe/p_state.h" 42 #include "pipe/p_video_codec.h" 43 44 #include "util/u_inlines.h" 45 46 #include "st_vdpau.h" 47 #include "st_context.h" 48 #include "st_sampler_view.h" 49 #include "st_texture.h" 50 #include "st_format.h" 51 #include "st_cb_flush.h" 52 53 #include "state_tracker/vdpau_interop.h" 54 #include "state_tracker/vdpau_dmabuf.h" 55 #include "state_tracker/vdpau_funcs.h" 56 #include "state_tracker/drm_driver.h" 57 58 static struct pipe_resource * 59 st_vdpau_video_surface_gallium(struct gl_context *ctx, const void *vdpSurface, 60 GLuint index) 61 { 62 int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr); 63 uint32_t device = (uintptr_t)ctx->vdpDevice; 64 struct pipe_sampler_view *sv; 65 VdpVideoSurfaceGallium *f; 66 67 struct pipe_video_buffer *buffer; 68 struct pipe_sampler_view **samplers; 69 struct pipe_resource *res = NULL; 70 71 getProcAddr = (void *)ctx->vdpGetProcAddress; 72 if (getProcAddr(device, VDP_FUNC_ID_VIDEO_SURFACE_GALLIUM, (void**)&f)) 73 return NULL; 74 75 buffer = f((uintptr_t)vdpSurface); 76 if (!buffer) 77 return NULL; 78 79 samplers = buffer->get_sampler_view_planes(buffer); 80 if (!samplers) 81 return NULL; 82 83 sv = samplers[index >> 1]; 84 if (!sv) 85 return NULL; 86 87 pipe_resource_reference(&res, sv->texture); 88 return res; 89 } 90 91 static struct pipe_resource * 92 st_vdpau_output_surface_gallium(struct gl_context *ctx, const void *vdpSurface) 93 { 94 int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr); 95 uint32_t device = (uintptr_t)ctx->vdpDevice; 96 struct pipe_resource *res = NULL; 97 VdpOutputSurfaceGallium *f; 98 99 getProcAddr = (void *)ctx->vdpGetProcAddress; 100 if (getProcAddr(device, VDP_FUNC_ID_OUTPUT_SURFACE_GALLIUM, (void**)&f)) 101 return NULL; 102 103 pipe_resource_reference(&res, f((uintptr_t)vdpSurface)); 104 return res; 105 } 106 107 static struct pipe_resource * 108 st_vdpau_resource_from_description(struct gl_context *ctx, 109 const struct VdpSurfaceDMABufDesc *desc) 110 { 111 struct st_context *st = st_context(ctx); 112 struct pipe_resource templ, *res; 113 struct winsys_handle whandle; 114 115 if (desc->handle == -1) 116 return NULL; 117 118 memset(&templ, 0, sizeof(templ)); 119 templ.target = PIPE_TEXTURE_2D; 120 templ.last_level = 0; 121 templ.depth0 = 1; 122 templ.array_size = 1; 123 templ.width0 = desc->width; 124 templ.height0 = desc->height; 125 templ.format = VdpFormatRGBAToPipe(desc->format); 126 templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; 127 templ.usage = PIPE_USAGE_DEFAULT; 128 129 memset(&whandle, 0, sizeof(whandle)); 130 whandle.type = DRM_API_HANDLE_TYPE_FD; 131 whandle.handle = desc->handle; 132 whandle.offset = desc->offset; 133 whandle.stride = desc->stride; 134 135 res = st->pipe->screen->resource_from_handle(st->pipe->screen, &templ, &whandle, 136 PIPE_HANDLE_USAGE_READ_WRITE); 137 close(desc->handle); 138 139 return res; 140 } 141 142 static struct pipe_resource * 143 st_vdpau_output_surface_dma_buf(struct gl_context *ctx, const void *vdpSurface) 144 { 145 int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr); 146 uint32_t device = (uintptr_t)ctx->vdpDevice; 147 148 struct VdpSurfaceDMABufDesc desc; 149 VdpOutputSurfaceDMABuf *f; 150 151 getProcAddr = (void *)ctx->vdpGetProcAddress; 152 if (getProcAddr(device, VDP_FUNC_ID_OUTPUT_SURFACE_DMA_BUF, (void**)&f)) 153 return NULL; 154 155 if (f((uintptr_t)vdpSurface, &desc) != VDP_STATUS_OK) 156 return NULL; 157 158 return st_vdpau_resource_from_description(ctx, &desc); 159 } 160 161 static struct pipe_resource * 162 st_vdpau_video_surface_dma_buf(struct gl_context *ctx, const void *vdpSurface, 163 GLuint index) 164 { 165 int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr); 166 uint32_t device = (uintptr_t)ctx->vdpDevice; 167 168 struct VdpSurfaceDMABufDesc desc; 169 VdpVideoSurfaceDMABuf *f; 170 171 getProcAddr = (void *)ctx->vdpGetProcAddress; 172 if (getProcAddr(device, VDP_FUNC_ID_VIDEO_SURFACE_DMA_BUF, (void**)&f)) 173 return NULL; 174 175 if (f((uintptr_t)vdpSurface, index, &desc) != VDP_STATUS_OK) 176 return NULL; 177 178 return st_vdpau_resource_from_description(ctx, &desc); 179 } 180 181 static void 182 st_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access, 183 GLboolean output, struct gl_texture_object *texObj, 184 struct gl_texture_image *texImage, 185 const void *vdpSurface, GLuint index) 186 { 187 struct st_context *st = st_context(ctx); 188 struct st_texture_object *stObj = st_texture_object(texObj); 189 struct st_texture_image *stImage = st_texture_image(texImage); 190 191 struct pipe_resource *res; 192 mesa_format texFormat; 193 uint layer_override = 0; 194 195 if (output) { 196 res = st_vdpau_output_surface_dma_buf(ctx, vdpSurface); 197 198 if (!res) 199 res = st_vdpau_output_surface_gallium(ctx, vdpSurface); 200 201 } else { 202 res = st_vdpau_video_surface_dma_buf(ctx, vdpSurface, index); 203 204 if (!res) { 205 res = st_vdpau_video_surface_gallium(ctx, vdpSurface, index); 206 layer_override = index & 1; 207 } 208 } 209 210 if (!res) { 211 _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); 212 return; 213 } 214 215 /* do we have different screen objects ? */ 216 if (res->screen != st->pipe->screen) { 217 _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); 218 pipe_resource_reference(&res, NULL); 219 return; 220 } 221 222 /* switch to surface based */ 223 if (!stObj->surface_based) { 224 _mesa_clear_texture_object(ctx, texObj, NULL); 225 stObj->surface_based = GL_TRUE; 226 } 227 228 texFormat = st_pipe_format_to_mesa_format(res->format); 229 230 _mesa_init_teximage_fields(ctx, texImage, 231 res->width0, res->height0, 1, 0, GL_RGBA, 232 texFormat); 233 234 pipe_resource_reference(&stObj->pt, res); 235 st_texture_release_all_sampler_views(st, stObj); 236 pipe_resource_reference(&stImage->pt, res); 237 238 stObj->surface_format = res->format; 239 stObj->level_override = 0; 240 stObj->layer_override = layer_override; 241 242 _mesa_dirty_texobj(ctx, texObj); 243 pipe_resource_reference(&res, NULL); 244 } 245 246 static void 247 st_vdpau_unmap_surface(struct gl_context *ctx, GLenum target, GLenum access, 248 GLboolean output, struct gl_texture_object *texObj, 249 struct gl_texture_image *texImage, 250 const void *vdpSurface, GLuint index) 251 { 252 struct st_context *st = st_context(ctx); 253 struct st_texture_object *stObj = st_texture_object(texObj); 254 struct st_texture_image *stImage = st_texture_image(texImage); 255 256 pipe_resource_reference(&stObj->pt, NULL); 257 st_texture_release_all_sampler_views(st, stObj); 258 pipe_resource_reference(&stImage->pt, NULL); 259 260 stObj->level_override = 0; 261 stObj->layer_override = 0; 262 263 _mesa_dirty_texobj(ctx, texObj); 264 265 /* NV_vdpau_interop does not specify an explicit synchronization mechanism 266 * between the GL and VDPAU contexts. Provide automatic synchronization here. 267 */ 268 st_flush(st, NULL, 0); 269 } 270 271 void 272 st_init_vdpau_functions(struct dd_function_table *functions) 273 { 274 functions->VDPAUMapSurface = st_vdpau_map_surface; 275 functions->VDPAUUnmapSurface = st_vdpau_unmap_surface; 276 } 277 #endif 278