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