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