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