• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdbool.h>
35 #include "util/hash_table.h"
36 #include "util/set.h"
37 #include "context.h"
38 #include "glformats.h"
39 #include "texobj.h"
40 #include "teximage.h"
41 #include "vdpau.h"
42 
43 #define MAX_TEXTURES 4
44 
45 struct vdp_surface
46 {
47    GLenum target;
48    struct gl_texture_object *textures[MAX_TEXTURES];
49    GLenum access, state;
50    GLboolean output;
51    const GLvoid *vdpSurface;
52 };
53 
54 void GLAPIENTRY
_mesa_VDPAUInitNV(const GLvoid * vdpDevice,const GLvoid * getProcAddress)55 _mesa_VDPAUInitNV(const GLvoid *vdpDevice, const GLvoid *getProcAddress)
56 {
57    GET_CURRENT_CONTEXT(ctx);
58 
59    if (!vdpDevice) {
60       _mesa_error(ctx, GL_INVALID_VALUE, "vdpDevice");
61       return;
62    }
63 
64    if (!getProcAddress) {
65       _mesa_error(ctx, GL_INVALID_VALUE, "getProcAddress");
66       return;
67    }
68 
69    if (ctx->vdpDevice || ctx->vdpGetProcAddress || ctx->vdpSurfaces) {
70       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUInitNV");
71       return;
72    }
73 
74    ctx->vdpDevice = vdpDevice;
75    ctx->vdpGetProcAddress = getProcAddress;
76    ctx->vdpSurfaces = _mesa_set_create(NULL, _mesa_hash_pointer,
77                                        _mesa_key_pointer_equal);
78 }
79 
80 static void
unregister_surface(struct set_entry * entry)81 unregister_surface(struct set_entry *entry)
82 {
83    struct vdp_surface *surf = (struct vdp_surface *)entry->key;
84    GET_CURRENT_CONTEXT(ctx);
85 
86    if (surf->state == GL_SURFACE_MAPPED_NV) {
87       GLintptr surfaces[] = { (GLintptr)surf };
88       _mesa_VDPAUUnmapSurfacesNV(1, surfaces);
89    }
90 
91    _mesa_set_remove(ctx->vdpSurfaces, entry);
92    free(surf);
93 }
94 
95 void GLAPIENTRY
_mesa_VDPAUFiniNV(void)96 _mesa_VDPAUFiniNV(void)
97 {
98    GET_CURRENT_CONTEXT(ctx);
99 
100    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
101       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUFiniNV");
102       return;
103    }
104 
105    _mesa_set_destroy(ctx->vdpSurfaces, unregister_surface);
106 
107    ctx->vdpDevice = 0;
108    ctx->vdpGetProcAddress = 0;
109    ctx->vdpSurfaces = NULL;
110 }
111 
112 static GLintptr
register_surface(struct gl_context * ctx,GLboolean isOutput,const GLvoid * vdpSurface,GLenum target,GLsizei numTextureNames,const GLuint * textureNames)113 register_surface(struct gl_context *ctx, GLboolean isOutput,
114                  const GLvoid *vdpSurface, GLenum target,
115                  GLsizei numTextureNames, const GLuint *textureNames)
116 {
117    struct vdp_surface *surf;
118    int i;
119 
120    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
121       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV");
122       return (GLintptr)NULL;
123    }
124 
125    if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE) {
126       _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
127       return (GLintptr)NULL;
128    }
129 
130    if (target == GL_TEXTURE_RECTANGLE && !ctx->Extensions.NV_texture_rectangle) {
131       _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
132       return (GLintptr)NULL;
133    }
134 
135    surf = CALLOC_STRUCT( vdp_surface );
136    if (surf == NULL) {
137       _mesa_error_no_memory("VDPAURegisterSurfaceNV");
138       return (GLintptr)NULL;
139    }
140 
141    surf->vdpSurface = vdpSurface;
142    surf->target = target;
143    surf->access = GL_READ_WRITE;
144    surf->state = GL_SURFACE_REGISTERED_NV;
145    surf->output = isOutput;
146    for (i = 0; i < numTextureNames; ++i) {
147       struct gl_texture_object *tex;
148       tex  = _mesa_lookup_texture(ctx, textureNames[i]);
149       if (tex == NULL) {
150          free(surf);
151          _mesa_error(ctx, GL_INVALID_OPERATION,
152                      "VDPAURegisterSurfaceNV(texture ID not found)");
153          return (GLintptr)NULL;
154       }
155 
156       _mesa_lock_texture(ctx, tex);
157 
158       if (tex->Immutable) {
159          _mesa_unlock_texture(ctx, tex);
160          free(surf);
161          _mesa_error(ctx, GL_INVALID_OPERATION,
162                      "VDPAURegisterSurfaceNV(texture is immutable)");
163          return (GLintptr)NULL;
164       }
165 
166       if (tex->Target == 0) {
167          tex->Target = target;
168          tex->TargetIndex = _mesa_tex_target_to_index(ctx, target);
169       } else if (tex->Target != target) {
170          _mesa_unlock_texture(ctx, tex);
171          free(surf);
172          _mesa_error(ctx, GL_INVALID_OPERATION,
173                      "VDPAURegisterSurfaceNV(target mismatch)");
174          return (GLintptr)NULL;
175       }
176 
177       /* This will disallow respecifying the storage. */
178       tex->Immutable = GL_TRUE;
179       _mesa_unlock_texture(ctx, tex);
180 
181       _mesa_reference_texobj(&surf->textures[i], tex);
182    }
183 
184    _mesa_set_add(ctx->vdpSurfaces, surf);
185 
186    return (GLintptr)surf;
187 }
188 
189 GLintptr GLAPIENTRY
_mesa_VDPAURegisterVideoSurfaceNV(const GLvoid * vdpSurface,GLenum target,GLsizei numTextureNames,const GLuint * textureNames)190 _mesa_VDPAURegisterVideoSurfaceNV(const GLvoid *vdpSurface, GLenum target,
191                                   GLsizei numTextureNames,
192                                   const GLuint *textureNames)
193 {
194    GET_CURRENT_CONTEXT(ctx);
195 
196    if (numTextureNames != 4) {
197       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAURegisterVideoSurfaceNV");
198       return (GLintptr)NULL;
199    }
200 
201    return register_surface(ctx, false, vdpSurface, target,
202                            numTextureNames, textureNames);
203 }
204 
205 GLintptr GLAPIENTRY
_mesa_VDPAURegisterOutputSurfaceNV(const GLvoid * vdpSurface,GLenum target,GLsizei numTextureNames,const GLuint * textureNames)206 _mesa_VDPAURegisterOutputSurfaceNV(const GLvoid *vdpSurface, GLenum target,
207                                    GLsizei numTextureNames,
208                                    const GLuint *textureNames)
209 {
210    GET_CURRENT_CONTEXT(ctx);
211 
212    if (numTextureNames != 1) {
213       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAURegisterVideoSurfaceNV");
214       return (GLintptr)NULL;
215    }
216 
217    return register_surface(ctx, true, vdpSurface, target,
218                            numTextureNames, textureNames);
219 }
220 
221 GLboolean GLAPIENTRY
_mesa_VDPAUIsSurfaceNV(GLintptr surface)222 _mesa_VDPAUIsSurfaceNV(GLintptr surface)
223 {
224    struct vdp_surface *surf = (struct vdp_surface *)surface;
225    GET_CURRENT_CONTEXT(ctx);
226 
227    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
228       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUIsSurfaceNV");
229       return false;
230    }
231 
232    if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
233       return false;
234    }
235 
236    return true;
237 }
238 
239 void GLAPIENTRY
_mesa_VDPAUUnregisterSurfaceNV(GLintptr surface)240 _mesa_VDPAUUnregisterSurfaceNV(GLintptr surface)
241 {
242    struct vdp_surface *surf = (struct vdp_surface *)surface;
243    struct set_entry *entry;
244    int i;
245    GET_CURRENT_CONTEXT(ctx);
246 
247    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
248       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUUnregisterSurfaceNV");
249       return;
250    }
251 
252    /* according to the spec it's ok when this is zero */
253    if (surface == 0)
254       return;
255 
256    entry = _mesa_set_search(ctx->vdpSurfaces, surf);
257    if (!entry) {
258       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUUnregisterSurfaceNV");
259       return;
260    }
261 
262    for (i = 0; i < MAX_TEXTURES; i++) {
263       if (surf->textures[i]) {
264          surf->textures[i]->Immutable = GL_FALSE;
265          _mesa_reference_texobj(&surf->textures[i], NULL);
266       }
267    }
268 
269    _mesa_set_remove(ctx->vdpSurfaces, entry);
270    free(surf);
271 }
272 
273 void GLAPIENTRY
_mesa_VDPAUGetSurfaceivNV(GLintptr surface,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * values)274 _mesa_VDPAUGetSurfaceivNV(GLintptr surface, GLenum pname, GLsizei bufSize,
275                           GLsizei *length, GLint *values)
276 {
277    struct vdp_surface *surf = (struct vdp_surface *)surface;
278    GET_CURRENT_CONTEXT(ctx);
279 
280    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
281       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUGetSurfaceivNV");
282       return;
283    }
284 
285    if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
286       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUGetSurfaceivNV");
287       return;
288    }
289 
290    if (pname != GL_SURFACE_STATE_NV) {
291       _mesa_error(ctx, GL_INVALID_ENUM, "VDPAUGetSurfaceivNV");
292       return;
293    }
294 
295    if (bufSize < 1) {
296       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUGetSurfaceivNV");
297       return;
298    }
299 
300    values[0] = surf->state;
301 
302    if (length != NULL)
303       *length = 1;
304 }
305 
306 void GLAPIENTRY
_mesa_VDPAUSurfaceAccessNV(GLintptr surface,GLenum access)307 _mesa_VDPAUSurfaceAccessNV(GLintptr surface, GLenum access)
308 {
309    struct vdp_surface *surf = (struct vdp_surface *)surface;
310    GET_CURRENT_CONTEXT(ctx);
311 
312    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
313       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
314       return;
315    }
316 
317    if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
318       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
319       return;
320    }
321 
322    if (access != GL_READ_ONLY && access != GL_WRITE_ONLY &&
323        access != GL_READ_WRITE) {
324 
325       _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
326       return;
327    }
328 
329    if (surf->state == GL_SURFACE_MAPPED_NV) {
330       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
331       return;
332    }
333 
334    surf->access = access;
335 }
336 
337 void GLAPIENTRY
_mesa_VDPAUMapSurfacesNV(GLsizei numSurfaces,const GLintptr * surfaces)338 _mesa_VDPAUMapSurfacesNV(GLsizei numSurfaces, const GLintptr *surfaces)
339 {
340    GET_CURRENT_CONTEXT(ctx);
341    int i;
342 
343    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
344       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUUnmapSurfacesNV");
345       return;
346    }
347 
348    for (i = 0; i < numSurfaces; ++i) {
349       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
350 
351       if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
352          _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
353          return;
354       }
355 
356       if (surf->state == GL_SURFACE_MAPPED_NV) {
357          _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
358          return;
359       }
360    }
361 
362    for (i = 0; i < numSurfaces; ++i) {
363       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
364       unsigned numTextureNames = surf->output ? 1 : 4;
365       unsigned j;
366 
367       for (j = 0; j < numTextureNames; ++j) {
368          struct gl_texture_object *tex = surf->textures[j];
369          struct gl_texture_image *image;
370 
371          _mesa_lock_texture(ctx, tex);
372          image = _mesa_get_tex_image(ctx, tex, surf->target, 0);
373          if (!image) {
374             _mesa_error(ctx, GL_OUT_OF_MEMORY, "VDPAUMapSurfacesNV");
375             _mesa_unlock_texture(ctx, tex);
376             return;
377          }
378 
379          ctx->Driver.FreeTextureImageBuffer(ctx, image);
380 
381          ctx->Driver.VDPAUMapSurface(ctx, surf->target, surf->access,
382                                      surf->output, tex, image,
383                                      surf->vdpSurface, j);
384 
385          _mesa_unlock_texture(ctx, tex);
386       }
387       surf->state = GL_SURFACE_MAPPED_NV;
388    }
389 }
390 
391 void GLAPIENTRY
_mesa_VDPAUUnmapSurfacesNV(GLsizei numSurfaces,const GLintptr * surfaces)392 _mesa_VDPAUUnmapSurfacesNV(GLsizei numSurfaces, const GLintptr *surfaces)
393 {
394    GET_CURRENT_CONTEXT(ctx);
395    int i;
396 
397    if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
398       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUUnmapSurfacesNV");
399       return;
400    }
401 
402    for (i = 0; i < numSurfaces; ++i) {
403       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
404 
405       if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
406          _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
407          return;
408       }
409 
410       if (surf->state != GL_SURFACE_MAPPED_NV) {
411          _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
412          return;
413       }
414    }
415 
416    for (i = 0; i < numSurfaces; ++i) {
417       struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
418       unsigned numTextureNames = surf->output ? 1 : 4;
419       unsigned j;
420 
421       for (j = 0; j < numTextureNames; ++j) {
422          struct gl_texture_object *tex = surf->textures[j];
423          struct gl_texture_image *image;
424 
425          _mesa_lock_texture(ctx, tex);
426 
427          image = _mesa_select_tex_image(tex, surf->target, 0);
428 
429          ctx->Driver.VDPAUUnmapSurface(ctx, surf->target, surf->access,
430                                        surf->output, tex, image,
431                                        surf->vdpSurface, j);
432 
433          if (image)
434             ctx->Driver.FreeTextureImageBuffer(ctx, image);
435 
436          _mesa_unlock_texture(ctx, tex);
437       }
438       surf->state = GL_SURFACE_REGISTERED_NV;
439    }
440 }
441