/* * Copyright © 2016 Red Hat. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "macros.h" #include "mtypes.h" #include "bufferobj.h" #include "context.h" #include "externalobjects.h" #include "teximage.h" #include "texobj.h" #include "glformats.h" #include "texstorage.h" #include "util/u_memory.h" /** * Allocate and initialize a new memory object. But don't put it into the * memory object hash table. * * Called via ctx->Driver.NewMemoryObject, unless overridden by a device * driver. * * \return pointer to new memory object. */ static struct gl_memory_object * _mesa_new_memory_object(struct gl_context *ctx, GLuint name) { struct gl_memory_object *obj = MALLOC_STRUCT(gl_memory_object); if (!obj) return NULL; _mesa_initialize_memory_object(ctx, obj, name); return obj; } /** * Delete a memory object. Called via ctx->Driver.DeleteMemory(). * Not removed from hash table here. */ void _mesa_delete_memory_object(struct gl_context *ctx, struct gl_memory_object *memObj) { free(memObj); } void _mesa_init_memory_object_functions(struct dd_function_table *driver) { driver->NewMemoryObject = _mesa_new_memory_object; driver->DeleteMemoryObject = _mesa_delete_memory_object; } /** * Initialize a buffer object to default values. */ void _mesa_initialize_memory_object(struct gl_context *ctx, struct gl_memory_object *obj, GLuint name) { memset(obj, 0, sizeof(struct gl_memory_object)); obj->Name = name; obj->Dedicated = GL_FALSE; } void GLAPIENTRY _mesa_DeleteMemoryObjectsEXT(GLsizei n, const GLuint *memoryObjects) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & (VERBOSE_API)) { _mesa_debug(ctx, "glDeleteMemoryObjectsEXT(%d, %p)\n", n, memoryObjects); } if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteMemoryObjectsEXT(unsupported)"); return; } if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteMemoryObjectsEXT(n < 0)"); return; } if (!memoryObjects) return; _mesa_HashLockMutex(ctx->Shared->MemoryObjects); for (GLint i = 0; i < n; i++) { if (memoryObjects[i] > 0) { struct gl_memory_object *delObj = _mesa_lookup_memory_object_locked(ctx, memoryObjects[i]); if (delObj) { _mesa_HashRemoveLocked(ctx->Shared->MemoryObjects, memoryObjects[i]); ctx->Driver.DeleteMemoryObject(ctx, delObj); } } } _mesa_HashUnlockMutex(ctx->Shared->MemoryObjects); } GLboolean GLAPIENTRY _mesa_IsMemoryObjectEXT(GLuint memoryObject) { GET_CURRENT_CONTEXT(ctx); if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "glIsMemoryObjectEXT(unsupported)"); return GL_FALSE; } struct gl_memory_object *obj = _mesa_lookup_memory_object(ctx, memoryObject); return obj ? GL_TRUE : GL_FALSE; } void GLAPIENTRY _mesa_CreateMemoryObjectsEXT(GLsizei n, GLuint *memoryObjects) { GET_CURRENT_CONTEXT(ctx); const char *func = "glCreateMemoryObjectsEXT"; if (MESA_VERBOSE & (VERBOSE_API)) _mesa_debug(ctx, "%s(%d, %p)", func, n, memoryObjects); if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; } if (!memoryObjects) return; _mesa_HashLockMutex(ctx->Shared->MemoryObjects); GLuint first = _mesa_HashFindFreeKeyBlock(ctx->Shared->MemoryObjects, n); if (first) { for (GLsizei i = 0; i < n; i++) { struct gl_memory_object *memObj; memoryObjects[i] = first + i; /* allocate memory object */ memObj = ctx->Driver.NewMemoryObject(ctx, memoryObjects[i]); if (!memObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", func); _mesa_HashUnlockMutex(ctx->Shared->MemoryObjects); return; } /* insert into hash table */ _mesa_HashInsertLocked(ctx->Shared->MemoryObjects, memoryObjects[i], memObj); } } _mesa_HashUnlockMutex(ctx->Shared->MemoryObjects); } void GLAPIENTRY _mesa_MemoryObjectParameterivEXT(GLuint memoryObject, GLenum pname, const GLint *params) { GET_CURRENT_CONTEXT(ctx); struct gl_memory_object *memObj; const char *func = "glMemoryObjectParameterivEXT"; if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } memObj = _mesa_lookup_memory_object(ctx, memoryObject); if (!memObj) return; if (memObj->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(memoryObject is immutable", func); return; } switch (pname) { case GL_DEDICATED_MEMORY_OBJECT_EXT: memObj->Dedicated = (GLboolean) params[0]; break; case GL_PROTECTED_MEMORY_OBJECT_EXT: /* EXT_protected_textures not supported */ goto invalid_pname; default: goto invalid_pname; } return; invalid_pname: _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); } void GLAPIENTRY _mesa_GetMemoryObjectParameterivEXT(GLuint memoryObject, GLenum pname, GLint *params) { GET_CURRENT_CONTEXT(ctx); struct gl_memory_object *memObj; const char *func = "glMemoryObjectParameterivEXT"; if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } memObj = _mesa_lookup_memory_object(ctx, memoryObject); if (!memObj) return; switch (pname) { case GL_DEDICATED_MEMORY_OBJECT_EXT: *params = (GLint) memObj->Dedicated; break; case GL_PROTECTED_MEMORY_OBJECT_EXT: /* EXT_protected_textures not supported */ goto invalid_pname; default: goto invalid_pname; } return; invalid_pname: _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); } static struct gl_memory_object * lookup_memory_object_err(struct gl_context *ctx, unsigned memory, const char* func) { if (memory == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(memory=0)", func); return NULL; } struct gl_memory_object *memObj = _mesa_lookup_memory_object(ctx, memory); if (!memObj) return NULL; if (!memObj->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no associated memory)", func); return NULL; } return memObj; } /** * Helper used by _mesa_TexStorageMem1/2/3DEXT(). */ static void texstorage_memory(GLuint dims, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, const char *func) { struct gl_texture_object *texObj; struct gl_memory_object *memObj; GET_CURRENT_CONTEXT(ctx); if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; memObj = lookup_memory_object_err(ctx, memory, func); if (!memObj) return; _mesa_texture_storage_memory(ctx, dims, texObj, memObj, target, levels, internalFormat, width, height, depth, offset, false); } static void texstorage_memory_ms(GLuint dims, GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset, const char* func) { struct gl_texture_object *texObj; struct gl_memory_object *memObj; GET_CURRENT_CONTEXT(ctx); if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; memObj = lookup_memory_object_err(ctx, memory, func); if (!memObj) return; _mesa_texture_storage_ms_memory(ctx, dims, texObj, memObj, target, samples, internalFormat, width, height, depth, fixedSampleLocations, offset, func); } /** * Helper used by _mesa_TextureStorageMem1/2/3DEXT(). */ static void texturestorage_memory(GLuint dims, GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, const char *func) { struct gl_texture_object *texObj; struct gl_memory_object *memObj; GET_CURRENT_CONTEXT(ctx); if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } texObj = _mesa_lookup_texture(ctx, texture); if (!texObj) return; memObj = lookup_memory_object_err(ctx, memory, func); if (!memObj) return; _mesa_texture_storage_memory(ctx, dims, texObj, memObj, texObj->Target, levels, internalFormat, width, height, depth, offset, true); } static void texturestorage_memory_ms(GLuint dims, GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset, const char* func) { struct gl_texture_object *texObj; struct gl_memory_object *memObj; GET_CURRENT_CONTEXT(ctx); if (!ctx->Extensions.EXT_memory_object) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } texObj = _mesa_lookup_texture(ctx, texture); if (!texObj) return; memObj = lookup_memory_object_err(ctx, memory, func); if (!memObj) return; _mesa_texture_storage_ms_memory(ctx, dims, texObj, memObj, texObj->Target, samples, internalFormat, width, height, depth, fixedSampleLocations, offset, func); } void GLAPIENTRY _mesa_TexStorageMem2DEXT(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset) { texstorage_memory(2, target, levels, internalFormat, width, height, 1, memory, offset, "glTexStorageMem2DEXT"); } void GLAPIENTRY _mesa_TexStorageMem2DMultisampleEXT(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) { texstorage_memory_ms(2, target, samples, internalFormat, width, height, 1, fixedSampleLocations, memory, offset, "glTexStorageMem2DMultisampleEXT"); } void GLAPIENTRY _mesa_TexStorageMem3DEXT(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset) { texstorage_memory(3, target, levels, internalFormat, width, height, depth, memory, offset, "glTexStorageMem3DEXT"); } void GLAPIENTRY _mesa_TexStorageMem3DMultisampleEXT(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) { texstorage_memory_ms(3, target, samples, internalFormat, width, height, depth, fixedSampleLocations, memory, offset, "glTexStorageMem3DMultisampleEXT"); } void GLAPIENTRY _mesa_TextureStorageMem2DEXT(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset) { texturestorage_memory(2, texture, levels, internalFormat, width, height, 1, memory, offset, "glTexureStorageMem2DEXT"); } void GLAPIENTRY _mesa_TextureStorageMem2DMultisampleEXT(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) { texturestorage_memory_ms(2, texture, samples, internalFormat, width, height, 1, fixedSampleLocations, memory, offset, "glTextureStorageMem2DMultisampleEXT"); } void GLAPIENTRY _mesa_TextureStorageMem3DEXT(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset) { texturestorage_memory(3, texture, levels, internalFormat, width, height, depth, memory, offset, "glTextureStorageMem3DEXT"); } void GLAPIENTRY _mesa_TextureStorageMem3DMultisampleEXT(GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) { texturestorage_memory_ms(3, texture, samples, internalFormat, width, height, depth, fixedSampleLocations, memory, offset, "glTextureStorageMem3DMultisampleEXT"); } void GLAPIENTRY _mesa_TexStorageMem1DEXT(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset) { texstorage_memory(1, target, levels, internalFormat, width, 1, 1, memory, offset, "glTexStorageMem1DEXT"); } void GLAPIENTRY _mesa_TextureStorageMem1DEXT(GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset) { texturestorage_memory(1, texture, levels, internalFormat, width, 1, 1, memory, offset, "glTextureStorageMem1DEXT"); } /** * Used as a placeholder for semaphore objects between glGenSemaphoresEXT() * and glImportSemaphoreFdEXT(), so that glIsSemaphoreEXT() can work correctly. */ static struct gl_semaphore_object DummySemaphoreObject; /** * Delete a semaphore object. Called via ctx->Driver.DeleteSemaphore(). * Not removed from hash table here. */ void _mesa_delete_semaphore_object(struct gl_context *ctx, struct gl_semaphore_object *semObj) { if (semObj != &DummySemaphoreObject) free(semObj); } /** * Initialize a semaphore object to default values. */ void _mesa_initialize_semaphore_object(struct gl_context *ctx, struct gl_semaphore_object *obj, GLuint name) { memset(obj, 0, sizeof(struct gl_semaphore_object)); obj->Name = name; } void GLAPIENTRY _mesa_GenSemaphoresEXT(GLsizei n, GLuint *semaphores) { GET_CURRENT_CONTEXT(ctx); const char *func = "glGenSemaphoresEXT"; if (MESA_VERBOSE & (VERBOSE_API)) _mesa_debug(ctx, "%s(%d, %p)", func, n, semaphores); if (!ctx->Extensions.EXT_semaphore) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; } if (!semaphores) return; _mesa_HashLockMutex(ctx->Shared->SemaphoreObjects); GLuint first = _mesa_HashFindFreeKeyBlock(ctx->Shared->SemaphoreObjects, n); if (first) { for (GLsizei i = 0; i < n; i++) { semaphores[i] = first + i; _mesa_HashInsertLocked(ctx->Shared->SemaphoreObjects, semaphores[i], &DummySemaphoreObject); } } _mesa_HashUnlockMutex(ctx->Shared->SemaphoreObjects); } void GLAPIENTRY _mesa_DeleteSemaphoresEXT(GLsizei n, const GLuint *semaphores) { GET_CURRENT_CONTEXT(ctx); const char *func = "glDeleteSemaphoresEXT"; if (MESA_VERBOSE & (VERBOSE_API)) { _mesa_debug(ctx, "%s(%d, %p)\n", func, n, semaphores); } if (!ctx->Extensions.EXT_semaphore) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; } if (!semaphores) return; _mesa_HashLockMutex(ctx->Shared->SemaphoreObjects); for (GLint i = 0; i < n; i++) { if (semaphores[i] > 0) { struct gl_semaphore_object *delObj = _mesa_lookup_semaphore_object_locked(ctx, semaphores[i]); if (delObj) { _mesa_HashRemoveLocked(ctx->Shared->SemaphoreObjects, semaphores[i]); ctx->Driver.DeleteSemaphoreObject(ctx, delObj); } } } _mesa_HashUnlockMutex(ctx->Shared->SemaphoreObjects); } GLboolean GLAPIENTRY _mesa_IsSemaphoreEXT(GLuint semaphore) { GET_CURRENT_CONTEXT(ctx); if (!ctx->Extensions.EXT_semaphore) { _mesa_error(ctx, GL_INVALID_OPERATION, "glIsSemaphoreEXT(unsupported)"); return GL_FALSE; } struct gl_semaphore_object *obj = _mesa_lookup_semaphore_object(ctx, semaphore); return obj ? GL_TRUE : GL_FALSE; } /** * Helper that outputs the correct error status for parameter * calls where no pnames are defined */ static void semaphore_parameter_stub(const char* func, GLenum pname) { GET_CURRENT_CONTEXT(ctx); if (!ctx->Extensions.EXT_semaphore) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } /* EXT_semaphore and EXT_semaphore_fd define no parameters */ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname); } void GLAPIENTRY _mesa_SemaphoreParameterui64vEXT(GLuint semaphore, GLenum pname, const GLuint64 *params) { const char *func = "glSemaphoreParameterui64vEXT"; semaphore_parameter_stub(func, pname); } void GLAPIENTRY _mesa_GetSemaphoreParameterui64vEXT(GLuint semaphore, GLenum pname, GLuint64 *params) { const char *func = "glGetSemaphoreParameterui64vEXT"; semaphore_parameter_stub(func, pname); } void GLAPIENTRY _mesa_WaitSemaphoreEXT(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts) { GET_CURRENT_CONTEXT(ctx); struct gl_semaphore_object *semObj = NULL; struct gl_buffer_object **bufObjs = NULL; struct gl_texture_object **texObjs = NULL; const char *func = "glWaitSemaphoreEXT"; if (!ctx->Extensions.EXT_semaphore) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } ASSERT_OUTSIDE_BEGIN_END(ctx); semObj = _mesa_lookup_semaphore_object(ctx, semaphore); if (!semObj) return; FLUSH_VERTICES(ctx, 0); bufObjs = malloc(sizeof(struct gl_buffer_object *) * numBufferBarriers); if (!bufObjs) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numBufferBarriers=%u)", func, numBufferBarriers); goto end; } for (unsigned i = 0; i < numBufferBarriers; i++) { bufObjs[i] = _mesa_lookup_bufferobj(ctx, buffers[i]); } texObjs = malloc(sizeof(struct gl_texture_object *) * numTextureBarriers); if (!texObjs) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numTextureBarriers=%u)", func, numTextureBarriers); goto end; } for (unsigned i = 0; i < numTextureBarriers; i++) { texObjs[i] = _mesa_lookup_texture(ctx, textures[i]); } ctx->Driver.ServerWaitSemaphoreObject(ctx, semObj, numBufferBarriers, bufObjs, numTextureBarriers, texObjs, srcLayouts); end: free(bufObjs); free(texObjs); } void GLAPIENTRY _mesa_SignalSemaphoreEXT(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts) { GET_CURRENT_CONTEXT(ctx); struct gl_semaphore_object *semObj = NULL; struct gl_buffer_object **bufObjs = NULL; struct gl_texture_object **texObjs = NULL; const char *func = "glSignalSemaphoreEXT"; if (!ctx->Extensions.EXT_semaphore) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } ASSERT_OUTSIDE_BEGIN_END(ctx); semObj = _mesa_lookup_semaphore_object(ctx, semaphore); if (!semObj) return; FLUSH_VERTICES(ctx, 0); bufObjs = malloc(sizeof(struct gl_buffer_object *) * numBufferBarriers); if (!bufObjs) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numBufferBarriers=%u)", func, numBufferBarriers); goto end; } for (unsigned i = 0; i < numBufferBarriers; i++) { bufObjs[i] = _mesa_lookup_bufferobj(ctx, buffers[i]); } texObjs = malloc(sizeof(struct gl_texture_object *) * numTextureBarriers); if (!texObjs) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(numTextureBarriers=%u)", func, numTextureBarriers); goto end; } for (unsigned i = 0; i < numTextureBarriers; i++) { texObjs[i] = _mesa_lookup_texture(ctx, textures[i]); } ctx->Driver.ServerSignalSemaphoreObject(ctx, semObj, numBufferBarriers, bufObjs, numTextureBarriers, texObjs, dstLayouts); end: free(bufObjs); free(texObjs); } void GLAPIENTRY _mesa_ImportMemoryFdEXT(GLuint memory, GLuint64 size, GLenum handleType, GLint fd) { GET_CURRENT_CONTEXT(ctx); const char *func = "glImportMemoryFdEXT"; if (!ctx->Extensions.EXT_memory_object_fd) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } if (handleType != GL_HANDLE_TYPE_OPAQUE_FD_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType); return; } struct gl_memory_object *memObj = _mesa_lookup_memory_object(ctx, memory); if (!memObj) return; ctx->Driver.ImportMemoryObjectFd(ctx, memObj, size, fd); memObj->Immutable = GL_TRUE; } void GLAPIENTRY _mesa_ImportSemaphoreFdEXT(GLuint semaphore, GLenum handleType, GLint fd) { GET_CURRENT_CONTEXT(ctx); const char *func = "glImportSemaphoreFdEXT"; if (!ctx->Extensions.EXT_semaphore_fd) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); return; } if (handleType != GL_HANDLE_TYPE_OPAQUE_FD_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "%s(handleType=%u)", func, handleType); return; } struct gl_semaphore_object *semObj = _mesa_lookup_semaphore_object(ctx, semaphore); if (!semObj) return; if (semObj == &DummySemaphoreObject) { semObj = ctx->Driver.NewSemaphoreObject(ctx, semaphore); if (!semObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); return; } _mesa_HashInsert(ctx->Shared->SemaphoreObjects, semaphore, semObj); } ctx->Driver.ImportSemaphoreFd(ctx, semObj, fd); }