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