From: Andres Rodriguez <[email protected]> Used by EXT_external_objects and EXT_external_objects_fd
V2 (Timothy Arceri): - Throw GL_OUT_OF_MEMORY error if CreateMemoryObjectsEXT() fails. - C99 tidy ups - remove void cast (Constantine Kharlamov) V3 (Timothy Arceri): - rename mo -> memObj - check that the object is not NULL before initializing - add missing "EXT" in function error message V4 (Timothy Arceri): - remove checks for (memory objecy id == 0) and catch in _mesa_lookup_memory_object() instead. Signed-off-by: Andres Rodriguez <[email protected]> Reviewed-by: Timothy Arceri <[email protected]> Reviewed-by: Samuel Pitoiset <[email protected]> (v3) --- src/mesa/drivers/common/driverfuncs.c | 4 + src/mesa/main/dd.h | 36 +++++++++ src/mesa/main/externalobjects.c | 138 +++++++++++++++++++++++++++++++++- src/mesa/main/externalobjects.h | 31 ++++++++ src/mesa/main/mtypes.h | 9 +++ src/mesa/main/shared.c | 17 +++++ 6 files changed, 233 insertions(+), 2 deletions(-) diff --git a/src/mesa/drivers/common/driverfuncs.c b/src/mesa/drivers/common/driverfuncs.c index 5008ae8fea..ddb4bb6d6a 100644 --- a/src/mesa/drivers/common/driverfuncs.c +++ b/src/mesa/drivers/common/driverfuncs.c @@ -42,20 +42,21 @@ #include "main/teximage.h" #include "main/texobj.h" #include "main/texstorage.h" #include "main/texstore.h" #include "main/bufferobj.h" #include "main/fbobject.h" #include "main/samplerobj.h" #include "main/syncobj.h" #include "main/barrier.h" #include "main/transformfeedback.h" +#include "main/externalobjects.h" #include "program/program.h" #include "tnl/tnl.h" #include "swrast/swrast.h" #include "swrast/s_renderbuffer.h" #include "driverfuncs.h" #include "meta.h" @@ -159,20 +160,23 @@ _mesa_init_driver_functions(struct dd_function_table *driver) driver->Viewport = NULL; /* buffer objects */ _mesa_init_buffer_object_functions(driver); /* query objects */ _mesa_init_query_object_functions(driver); _mesa_init_sync_object_functions(driver); + /* memory objects */ + _mesa_init_memory_object_functions(driver); + driver->NewFramebuffer = _mesa_new_framebuffer; driver->NewRenderbuffer = _swrast_new_soft_renderbuffer; driver->MapRenderbuffer = _swrast_map_soft_renderbuffer; driver->UnmapRenderbuffer = _swrast_unmap_soft_renderbuffer; driver->RenderTexture = _swrast_render_texture; driver->FinishRenderTexture = _swrast_finish_render_texture; driver->FramebufferRenderbuffer = _mesa_FramebufferRenderbuffer_sw; driver->ValidateFramebuffer = _mesa_validate_framebuffer; driver->BlitFramebuffer = _swrast_BlitFramebuffer; diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 462829d755..6d6bdecb4d 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -1062,20 +1062,56 @@ struct dd_function_table { struct gl_sampler_object *sampObj); void (*DeleteTextureHandle)(struct gl_context *ctx, GLuint64 handle); void (*MakeTextureHandleResident)(struct gl_context *ctx, GLuint64 handle, bool resident); GLuint64 (*NewImageHandle)(struct gl_context *ctx, struct gl_image_unit *imgObj); void (*DeleteImageHandle)(struct gl_context *ctx, GLuint64 handle); void (*MakeImageHandleResident)(struct gl_context *ctx, GLuint64 handle, GLenum access, bool resident); /*@}*/ + + + /** + * \name GL_EXT_external_objects interface + */ + /*@{*/ + /** + * Called to allocate a new memory object. Drivers will usually + * allocate/return a subclass of gl_memory_object. + */ + struct gl_memory_object * (*NewMemoryObject)(struct gl_context *ctx, + GLuint name); + /** + * Called to delete/free a memory object. Drivers should free the + * object and any image data it contains. + */ + void (*DeleteMemoryObject)(struct gl_context *ctx, + struct gl_memory_object *memObj); + /*@}*/ + + /** + * \name GL_EXT_external_objects_fd interface + */ + /*@{*/ + /** + * Called to import a memory object. The caller relinquishes ownership + * of fd after the call returns. + * + * Accessing fd after ImportMemoryObjectFd returns results in undefined + * behaviour. This is consistent with EXT_external_object_fd. + */ + void (*ImportMemoryObjectFd)(struct gl_context *ctx, + struct gl_memory_object *memObj, + GLuint64 size, + int fd); + /*@}*/ }; /** * Per-vertex functions. * * These are the functions which can appear between glBegin and glEnd. * Depending on whether we're inside or outside a glBegin/End pair * and whether we're in immediate mode or building a display list, these * functions behave differently. This structure allows us to switch diff --git a/src/mesa/main/externalobjects.c b/src/mesa/main/externalobjects.c index 86404d2a8d..6bc07a5015 100644 --- a/src/mesa/main/externalobjects.c +++ b/src/mesa/main/externalobjects.c @@ -14,38 +14,160 @@ * * 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 "externalobjects.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; +} + 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 (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) { - return GL_FALSE; + GET_CURRENT_CONTEXT(ctx); + 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 (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); + goto out_unlock; + } + + /* insert into hash table */ + _mesa_HashInsertLocked(ctx->Shared->MemoryObjects, + memoryObjects[i], + memObj); + } + } + +out_unlock: + _mesa_HashUnlockMutex(ctx->Shared->MemoryObjects); } void GLAPIENTRY _mesa_MemoryObjectParameterivEXT(GLuint memoryObject, GLenum pname, const GLint *params) { } @@ -238,20 +360,32 @@ _mesa_SignalSemaphoreEXT(GLuint semaphore, { } void GLAPIENTRY _mesa_ImportMemoryFdEXT(GLuint memory, GLuint64 size, GLenum handleType, GLint fd) { + GET_CURRENT_CONTEXT(ctx); + + if (handleType != GL_HANDLE_TYPE_OPAQUE_FD_EXT) { + _mesa_error(ctx, GL_INVALID_VALUE, "glImportMemoryFdEXT(handleType=%u)", + handleType); + return; + } + + struct gl_memory_object *memObj = _mesa_lookup_memory_object(ctx, memory); + if (!memObj) + return; + ctx->Driver.ImportMemoryObjectFd(ctx, memObj, size, fd); } void GLAPIENTRY _mesa_ImportSemaphoreFdEXT(GLuint semaphore, GLenum handleType, GLint fd) { } diff --git a/src/mesa/main/externalobjects.h b/src/mesa/main/externalobjects.h index f70be8e8ab..a9a12b821f 100644 --- a/src/mesa/main/externalobjects.h +++ b/src/mesa/main/externalobjects.h @@ -28,20 +28,51 @@ /** * \file externalobjects.h * * Declarations of functions related to the API interop extensions. */ #ifndef EXTERNALOBJECTS_H #define EXTERNALOBJECTS_H #include "glheader.h" +#include "hash.h" + +static inline struct gl_memory_object * +_mesa_lookup_memory_object(struct gl_context *ctx, GLuint memory) +{ + if (!memory) + return NULL; + + return (struct gl_memory_object *) + _mesa_HashLookup(ctx->Shared->MemoryObjects, memory); +} + +static inline struct gl_memory_object * +_mesa_lookup_memory_object_locked(struct gl_context *ctx, GLuint memory) +{ + if (!memory) + return NULL; + + return (struct gl_memory_object *) + _mesa_HashLookupLocked(ctx->Shared->MemoryObjects, memory); +} + +extern void +_mesa_init_memory_object_functions(struct dd_function_table *driver); + +extern void +_mesa_initialize_memory_object(struct gl_context *ctx, + struct gl_memory_object *obj, + GLuint name); +extern void +_mesa_delete_memory_object(struct gl_context *ctx, struct gl_memory_object *mo); extern void GLAPIENTRY _mesa_DeleteMemoryObjectsEXT(GLsizei n, const GLuint *memoryObjects); extern GLboolean GLAPIENTRY _mesa_IsMemoryObjectEXT(GLuint memoryObject); extern void GLAPIENTRY _mesa_CreateMemoryObjectsEXT(GLsizei n, GLuint *memoryObjects); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 404d586ff7..b5ec6168a1 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -3267,20 +3267,24 @@ struct gl_shared_state /** * Some context in this share group was affected by a GPU reset * * On the next call to \c glGetGraphicsResetStatus, contexts that have not * been affected by a GPU reset must also return * \c GL_INNOCENT_CONTEXT_RESET_ARB. * * Once this field becomes true, it is never reset to false. */ bool ShareGroupReset; + + /** EXT_external_objects */ + struct _mesa_HashTable *MemoryObjects; + }; /** * Renderbuffers represent drawing surfaces such as color, depth and/or * stencil. A framebuffer object has a set of renderbuffers. * Drivers will typically derive subclasses of this type. */ struct gl_renderbuffer @@ -4633,20 +4637,25 @@ struct gl_texture_handle_object struct gl_sampler_object *sampObj; GLuint64 handle; }; struct gl_image_handle_object { struct gl_image_unit imgObj; GLuint64 handle; }; +struct gl_memory_object +{ + GLuint Name; /**< hash table ID/name */ +}; + /** * Mesa rendering context. * * This is the central context data structure for Mesa. Almost all * OpenGL state is contained in this structure. * Think of this as a base class from which device drivers will derive * sub classes. */ struct gl_context { diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c index 6926d40570..2cce47e226 100644 --- a/src/mesa/main/shared.c +++ b/src/mesa/main/shared.c @@ -123,20 +123,21 @@ _mesa_alloc_shared_state(struct gl_context *ctx) /* Mutex and timestamp for texobj state validation */ mtx_init(&shared->TexMutex, mtx_recursive); shared->TextureStateStamp = 0; shared->FrameBuffers = _mesa_NewHashTable(); shared->RenderBuffers = _mesa_NewHashTable(); shared->SyncObjects = _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); + shared->MemoryObjects = _mesa_NewHashTable(); return shared; } /** * Callback for deleting a display list. Called by _mesa_HashDeleteAll(). */ static void delete_displaylist_cb(GLuint id, void *data, void *userData) { @@ -288,20 +289,31 @@ delete_renderbuffer_cb(GLuint id, void *data, void *userData) * Callback for deleting a sampler object. Called by _mesa_HashDeleteAll() */ static void delete_sampler_object_cb(GLuint id, void *data, void *userData) { struct gl_context *ctx = (struct gl_context *) userData; struct gl_sampler_object *sampObj = (struct gl_sampler_object *) data; _mesa_reference_sampler_object(ctx, &sampObj, NULL); } +/** + * Callback for deleting a memory object. Called by _mesa_HashDeleteAll(). + */ +static void +delete_memory_object_cb(GLuint id, void *data, void *userData) +{ + struct gl_memory_object *memObj = (struct gl_memory_object *) data; + struct gl_context *ctx = (struct gl_context *) userData; + ctx->Driver.DeleteMemoryObject(ctx, memObj); +} + /** * Deallocate a shared state object and all children structures. * * \param ctx GL context. * \param shared shared state pointer. * * Frees the display lists, the texture objects (calling the driver texture * deletion callback to free its private data) and the vertex programs, as well * as their hash tables. @@ -372,20 +384,25 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared) for (i = 0; i < NUM_TEXTURE_TARGETS; i++) { ctx->Driver.DeleteTexture(ctx, shared->DefaultTex[i]); } /* all other textures */ _mesa_HashDeleteAll(shared->TexObjects, delete_texture_cb, ctx); _mesa_DeleteHashTable(shared->TexObjects); _mesa_free_shared_handles(shared); + if (shared->MemoryObjects) { + _mesa_HashDeleteAll(shared->MemoryObjects, delete_memory_object_cb, ctx); + _mesa_DeleteHashTable(shared->MemoryObjects); + } + mtx_destroy(&shared->Mutex); mtx_destroy(&shared->TexMutex); free(shared); } /** * gl_shared_state objects are ref counted. * If ptr's refcount goes to zero, free the shared state. -- 2.13.3 _______________________________________________ mesa-dev mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/mesa-dev
