xref: /third_party/mesa3d/src/mesa/main/vdpau.c (revision bf215546)
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
49struct 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
58void GLAPIENTRY
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
84static void
85unregister_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
99void GLAPIENTRY
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
116static GLintptr
117register_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
193GLintptr GLAPIENTRY
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
209GLintptr GLAPIENTRY
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
225GLboolean GLAPIENTRY
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
243void GLAPIENTRY
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
277void GLAPIENTRY
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
310void GLAPIENTRY
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
341void GLAPIENTRY
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
395void GLAPIENTRY
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