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