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