[Mesa-dev] [PATCH v2 03/64] mesa: implement ARB_bindless_texture

Samuel Pitoiset samuel.pitoiset at gmail.com
Tue May 30 20:35:34 UTC 2017


v2: - s/GLboolean/bool for HandleAllocated
    - fix _mesa_has_ARB_shader_image_load_store() checks
    - use u_vector for texture/image handles
    - fix use of 64-bit handles on 32-bit systems
    - some cleanups

Signed-off-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
---
 src/mesa/main/context.c         |   3 +
 src/mesa/main/dd.h              |  17 +
 src/mesa/main/mtypes.h          |  38 ++
 src/mesa/main/samplerobj.c      |   6 +
 src/mesa/main/shared.c          |   6 +
 src/mesa/main/texobj.c          |  13 +
 src/mesa/main/texturebindless.c | 927 +++++++++++++++++++++++++++++++++++++++-
 src/mesa/main/texturebindless.h |  32 ++
 8 files changed, 1035 insertions(+), 7 deletions(-)

diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 9aa6fb64b2..b801322fd0 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -133,6 +133,7 @@
 #include "varray.h"
 #include "version.h"
 #include "viewport.h"
+#include "texturebindless.h"
 #include "program/program.h"
 #include "math/m_matrix.h"
 #include "main/dispatch.h" /* for _gloffset_COUNT */
@@ -855,6 +856,7 @@ init_attrib_groups(struct gl_context *ctx)
    _mesa_init_transform_feedback( ctx );
    _mesa_init_varray( ctx );
    _mesa_init_viewport( ctx );
+   _mesa_init_resident_handles( ctx );
 
    if (!_mesa_init_texture( ctx ))
       return GL_FALSE;
@@ -1339,6 +1341,7 @@ _mesa_free_context_data( struct gl_context *ctx )
    _mesa_free_transform_feedback(ctx);
    _mesa_free_performance_monitors(ctx);
    _mesa_free_performance_queries(ctx);
+   _mesa_free_resident_handles(ctx);
 
    _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
    _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
index a9ca43d69e..d830f5184d 100644
--- a/src/mesa/main/dd.h
+++ b/src/mesa/main/dd.h
@@ -1050,6 +1050,23 @@ struct dd_function_table {
                                 GLintptr offset, GLsizeiptr size,
                                 GLboolean commit);
    /*@}*/
+
+   /**
+    * \name GL_ARB_bindless_texture interface
+    */
+   /*@{*/
+   GLuint64 (*NewTextureHandle)(struct gl_context *ctx,
+                                struct gl_texture_object *texObj,
+                                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);
+   /*@}*/
 };
 
 
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 29e4c67846..5b38eb1b64 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -47,6 +47,7 @@
 #include "main/formats.h"       /* MESA_FORMAT_COUNT */
 #include "compiler/glsl/list.h"
 #include "util/bitscan.h"
+#include "util/u_vector.h"
 
 
 #ifdef __cplusplus
@@ -987,6 +988,10 @@ struct gl_sampler_object
    GLenum CompareFunc;		/**< GL_ARB_shadow */
    GLenum sRGBDecode;           /**< GL_DECODE_EXT or GL_SKIP_DECODE_EXT */
    GLboolean CubeMapSeamless;   /**< GL_AMD_seamless_cubemap_per_texture */
+
+   /** GL_ARB_bindless_texture */
+   struct u_vector Handles;
+   bool HandleAllocated;
 };
 
 
@@ -1051,6 +1056,11 @@ struct gl_texture_object
 
    /** GL_ARB_shader_image_load_store */
    GLenum ImageFormatCompatibilityType;
+
+   /** GL_ARB_bindless_texture */
+   struct u_vector SamplerHandles;
+   struct u_vector ImageHandles;
+   bool HandleAllocated;
 };
 
 
@@ -1403,6 +1413,8 @@ struct gl_buffer_object
    unsigned MinMaxCacheHitIndices;
    unsigned MinMaxCacheMissIndices;
    bool MinMaxCacheDirty;
+
+   bool HandleAllocated; /**< GL_ARB_bindless_texture */
 };
 
 
@@ -3211,6 +3223,11 @@ struct gl_shared_state
    /** GL_ARB_sampler_objects */
    struct _mesa_HashTable *SamplerObjects;
 
+   /* GL_ARB_bindless_texture */
+   struct hash_table *TextureHandles;
+   struct hash_table *ImageHandles;
+   mtx_t HandlesMutex; /**< For texture/image handles safety */
+
    /**
     * Some context in this share group was affected by a GPU reset
     *
@@ -4500,6 +4517,19 @@ struct gl_subroutine_index_binding
    GLuint *IndexPtr;
 };
 
+struct gl_texture_handle_object
+{
+   struct gl_texture_object *texObj;
+   struct gl_sampler_object *sampObj;
+   GLuint64 handle;
+};
+
+struct gl_image_handle_object
+{
+   struct gl_image_unit imgObj;
+   GLuint64 handle;
+};
+
 /**
  * Mesa rendering context.
  *
@@ -4854,6 +4884,14 @@ struct gl_context
    GLfloat PrimitiveBoundingBox[8];
 
    struct disk_cache *Cache;
+
+   /**
+    * \name GL_ARB_bindless_texture
+    */
+   /*@{*/
+   struct hash_table *ResidentTextureHandles;
+   struct hash_table *ResidentImageHandles;
+   /*@}*/
 };
 
 /**
diff --git a/src/mesa/main/samplerobj.c b/src/mesa/main/samplerobj.c
index 63beaf1abb..ee15c68b4f 100644
--- a/src/mesa/main/samplerobj.c
+++ b/src/mesa/main/samplerobj.c
@@ -38,6 +38,7 @@
 #include "main/macros.h"
 #include "main/mtypes.h"
 #include "main/samplerobj.h"
+#include "main/texturebindless.h"
 
 
 struct gl_sampler_object *
@@ -61,6 +62,7 @@ static void
 delete_sampler_object(struct gl_context *ctx,
                       struct gl_sampler_object *sampObj)
 {
+   _mesa_delete_sampler_handles(ctx, sampObj);
    mtx_destroy(&sampObj->Mutex);
    free(sampObj->Label);
    free(sampObj);
@@ -132,6 +134,10 @@ _mesa_init_sampler_object(struct gl_sampler_object *sampObj, GLuint name)
    sampObj->CompareFunc = GL_LEQUAL;
    sampObj->sRGBDecode = GL_DECODE_EXT;
    sampObj->CubeMapSeamless = GL_FALSE;
+   sampObj->HandleAllocated = GL_FALSE;
+
+   /* GL_ARB_bindless_texture */
+   _mesa_init_sampler_handles(sampObj);
 }
 
 /**
diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c
index 5344812738..6926d40570 100644
--- a/src/mesa/main/shared.c
+++ b/src/mesa/main/shared.c
@@ -39,6 +39,7 @@
 #include "shaderapi.h"
 #include "shaderobj.h"
 #include "syncobj.h"
+#include "texturebindless.h"
 
 #include "util/hash_table.h"
 #include "util/set.h"
@@ -84,6 +85,9 @@ _mesa_alloc_shared_state(struct gl_context *ctx)
    /* GL_ARB_sampler_objects */
    shared->SamplerObjects = _mesa_NewHashTable();
 
+   /* GL_ARB_bindless_texture */
+   _mesa_init_shared_handles(shared);
+
    /* Allocate the default buffer object */
    shared->NullBufferObj = ctx->Driver.NewBufferObject(ctx, 0);
 
@@ -373,6 +377,8 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared)
    _mesa_HashDeleteAll(shared->TexObjects, delete_texture_cb, ctx);
    _mesa_DeleteHashTable(shared->TexObjects);
 
+   _mesa_free_shared_handles(shared);
+
    mtx_destroy(&shared->Mutex);
    mtx_destroy(&shared->TexMutex);
 
diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c
index 868e4eb7a2..1877262ed6 100644
--- a/src/mesa/main/texobj.c
+++ b/src/mesa/main/texobj.c
@@ -43,6 +43,7 @@
 #include "texstate.h"
 #include "mtypes.h"
 #include "program/prog_instruction.h"
+#include "texturebindless.h"
 
 
 
@@ -311,6 +312,7 @@ _mesa_initialize_texture_object( struct gl_context *ctx,
    obj->DepthMode = ctx->API == API_OPENGL_CORE ? GL_RED : GL_LUMINANCE;
    obj->StencilSampling = false;
    obj->Sampler.CubeMapSeamless = GL_FALSE;
+   obj->Sampler.HandleAllocated = GL_FALSE;
    obj->Swizzle[0] = GL_RED;
    obj->Swizzle[1] = GL_GREEN;
    obj->Swizzle[2] = GL_BLUE;
@@ -320,6 +322,9 @@ _mesa_initialize_texture_object( struct gl_context *ctx,
    obj->BufferObjectFormat = GL_R8;
    obj->_BufferObjectFormat = MESA_FORMAT_R_UNORM8;
    obj->ImageFormatCompatibilityType = GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE;
+
+   /* GL_ARB_bindless_texture */
+   _mesa_init_texture_handles(obj);
 }
 
 
@@ -397,6 +402,9 @@ _mesa_delete_texture_object(struct gl_context *ctx,
       }
    }
 
+   /* Delete all texture/image handles. */
+   _mesa_delete_texture_handles(ctx, texObj);
+
    _mesa_reference_buffer_object(ctx, &texObj->BufferObject, NULL);
 
    /* destroy the mutex -- it may have allocated memory (eg on bsd) */
@@ -1461,6 +1469,11 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures)
              */
             unbind_texobj_from_image_units(ctx, delObj);
 
+            /* Make all handles that reference this texture object non-resident
+             * in the current context.
+             */
+            _mesa_make_texture_handles_non_resident(ctx, delObj);
+
             _mesa_unlock_texture(ctx, delObj);
 
             ctx->NewState |= _NEW_TEXTURE_OBJECT;
diff --git a/src/mesa/main/texturebindless.c b/src/mesa/main/texturebindless.c
index 4d9c22d428..d5ef403851 100644
--- a/src/mesa/main/texturebindless.c
+++ b/src/mesa/main/texturebindless.c
@@ -25,61 +25,974 @@
 #include "context.h"
 #include "enums.h"
 #include "imports.h"
-#include "macros.h"
 #include "mtypes.h"
+#include "shaderimage.h"
+#include "teximage.h"
 #include "texobj.h"
 #include "texturebindless.h"
 
-#include "util/set.h"
+#include "util/macros.h"
 #include "util/hash_table.h"
 
+/**
+ * Hash table wrapper for 32-bit systems.
+ */
+
+#if !defined(MESA_ARCH_X86_64)
+
+struct hash_key {
+   GLuint64 value;
+};
+
+static uint32_t
+key_hash(const void *key)
+{
+   return _mesa_hash_data(key, sizeof(struct hash_key));
+}
+
+static bool
+key_equals(const void *a, const void *b)
+{
+   struct hash_key *aa = (struct hash_key *)a;
+   struct hash_key *bb = (struct hash_key *)b;
+
+   return aa->value == bb->value;
+}
+
+#endif
+
+static struct hash_entry *
+hash_table_search(struct hash_table *ht, GLuint64 key)
+{
+#if !defined(MESA_ARCH_X86_64)
+   struct hash_key *_key = NULL;
+   struct hash_entry *entry;
+
+   _key = CALLOC_STRUCT(hash_key);
+   if (!_key)
+      return NULL;
+   _key->value = key;
+
+   entry = _mesa_hash_table_search(ht, _key);
+
+   free(_key);
+   return entry;
+#else
+   return _mesa_hash_table_search(ht, (void *)key);
+#endif
+}
+
+static struct hash_entry *
+hash_table_insert(struct hash_table *ht, GLuint64 key, void *data)
+{
+#if !defined(MESA_ARCH_X86_64)
+   struct hash_key *_key = CALLOC_STRUCT(hash_key);
+
+   if (!_key)
+      return NULL;
+   _key->value = key;
+
+   return _mesa_hash_table_insert(ht, _key, data);
+#else
+   return _mesa_hash_table_insert(ht, (void *)key, data);
+#endif
+}
+
+static void
+hash_table_remove(struct hash_table *ht, struct hash_entry *entry)
+{
+#if !defined(MESA_ARCH_X86_64)
+   struct hash_key *_key = (struct hash_key *)entry->key;
+
+   _mesa_hash_table_remove(ht, entry);
+   free(_key);
+#else
+   _mesa_hash_table_remove(ht, entry);
+#endif
+}
+
+/**
+ * Return the gl_texture_handle_object for a given 64-bit handle.
+ */
+static struct gl_texture_handle_object *
+lookup_texture_handle(struct gl_context *ctx, GLuint64 id)
+{
+   struct hash_entry *entry;
+
+   mtx_lock(&ctx->Shared->HandlesMutex);
+   entry = hash_table_search(ctx->Shared->TextureHandles, id);
+   mtx_unlock(&ctx->Shared->HandlesMutex);
+
+   return entry ? (struct gl_texture_handle_object *)entry->data : NULL;
+}
+
+/**
+ * Return the gl_image_handle_object for a given 64-bit handle.
+ */
+static struct gl_image_handle_object *
+lookup_image_handle(struct gl_context *ctx, GLuint64 id)
+{
+   struct hash_entry *entry;
+
+   mtx_lock(&ctx->Shared->HandlesMutex);
+   entry = hash_table_search(ctx->Shared->ImageHandles, id);
+   mtx_unlock(&ctx->Shared->HandlesMutex);
+
+   return entry ? (struct gl_image_handle_object *)entry->data : NULL;
+}
+
+/**
+ * Delete a texture handle in the shared state.
+ */
+static void
+delete_texture_handle(struct gl_context *ctx, GLuint64 id)
+{
+   struct hash_entry *entry;
+
+   if (!lookup_texture_handle(ctx, id))
+      return;
+
+   mtx_lock(&ctx->Shared->HandlesMutex);
+   entry = hash_table_search(ctx->Shared->TextureHandles, id);
+   hash_table_remove(ctx->Shared->TextureHandles, entry);
+   mtx_unlock(&ctx->Shared->HandlesMutex);
+
+   ctx->Driver.DeleteTextureHandle(ctx, id);
+}
+
+/**
+ * Delete an image handle in the shared state.
+ */
+static void
+delete_image_handle(struct gl_context *ctx, GLuint64 id)
+{
+   struct hash_entry *entry;
+
+   if (!lookup_image_handle(ctx, id))
+      return;
+
+   mtx_lock(&ctx->Shared->HandlesMutex);
+   entry = hash_table_search(ctx->Shared->ImageHandles, id);
+   hash_table_remove(ctx->Shared->ImageHandles, entry);
+   mtx_unlock(&ctx->Shared->HandlesMutex);
+
+   ctx->Driver.DeleteImageHandle(ctx, id);
+}
+
+/**
+ * Return TRUE if the texture handle is resident in the current context.
+ */
+static inline bool
+is_texture_handle_resident(struct gl_context *ctx, GLuint64 handle)
+{
+   return hash_table_search(ctx->ResidentTextureHandles, handle) != NULL;
+}
+
+/**
+ * Return TRUE if the image handle is resident in the current context.
+ */
+static inline bool
+is_image_handle_resident(struct gl_context *ctx, GLuint64 handle)
+{
+   return hash_table_search(ctx->ResidentImageHandles, handle) != NULL;
+}
+
+/**
+ * Make a texture handle resident/non-resident in the current context.
+ */
+static void
+make_texture_handle_resident(struct gl_context *ctx,
+                             struct gl_texture_handle_object *texHandleObj,
+                             bool resident)
+{
+   GLuint64 handle = texHandleObj->handle;
+
+   if (resident) {
+      struct gl_sampler_object *sampObj = NULL;
+      struct gl_texture_object *texObj = NULL;
+
+      hash_table_insert(ctx->ResidentTextureHandles, handle, texHandleObj);
+
+      ctx->Driver.MakeTextureHandleResident(ctx, handle, GL_TRUE);
+
+      /* Reference the texture object (and the separate sampler if needed) to
+       * be sure it won't be deleted until it is not bound anywhere and there
+       * are no handles using the object that are resident in any context.
+       */
+      _mesa_reference_texobj(&texObj, texHandleObj->texObj);
+      if (texHandleObj->sampObj)
+         _mesa_reference_sampler_object(ctx, &sampObj, texHandleObj->sampObj);
+   } else {
+      struct hash_entry *entry;
+
+      entry = hash_table_search(ctx->ResidentTextureHandles, handle);
+      hash_table_remove(ctx->ResidentTextureHandles, entry);
+
+      ctx->Driver.MakeTextureHandleResident(ctx, handle, GL_FALSE);
+
+      /* Unreference the texture object (and the separate sampler if needed),
+       * if refcount hits zero, the texture and all handles will be deleted.
+       */
+      _mesa_reference_texobj(&texHandleObj->texObj, NULL);
+      if (texHandleObj->sampObj)
+         _mesa_reference_sampler_object(ctx, &texHandleObj->sampObj, NULL);
+   }
+}
+
+/**
+ * Make an image handle resident/non-resident in the current context.
+ */
+static void
+make_image_handle_resident(struct gl_context *ctx,
+                           struct gl_image_handle_object *imgHandleObj,
+                           GLenum access, bool resident)
+{
+   GLuint64 handle = imgHandleObj->handle;
+
+   if (resident) {
+      struct gl_texture_object *texObj = NULL;
+
+      hash_table_insert(ctx->ResidentImageHandles, handle, imgHandleObj);
+
+      ctx->Driver.MakeImageHandleResident(ctx, handle, access, GL_TRUE);
+
+      /* Reference the texture object to be sure it won't be deleted until it
+       * is not bound anywhere and there are no handles using the object that
+       * are resident in any context.
+       */
+      _mesa_reference_texobj(&texObj, imgHandleObj->imgObj.TexObj);
+   } else {
+      struct hash_entry *entry;
+
+      entry = hash_table_search(ctx->ResidentImageHandles, handle);
+      hash_table_remove(ctx->ResidentImageHandles, entry);
+
+      ctx->Driver.MakeImageHandleResident(ctx, handle, access, GL_FALSE);
+
+      /* Unreference the texture object, if refcount hits zero, the texture and
+       * all handles will be deleted.
+       */
+      _mesa_reference_texobj(&imgHandleObj->imgObj.TexObj, NULL);
+   }
+}
+
+static struct gl_texture_handle_object *
+find_texhandleobj(struct gl_texture_object *texObj,
+                  struct gl_sampler_object *sampObj)
+{
+   struct gl_texture_handle_object *texHandleObj;
+
+   u_vector_foreach(texHandleObj, &texObj->SamplerHandles) {
+      if (texHandleObj->sampObj == sampObj)
+         return texHandleObj;
+   }
+   return NULL;
+}
+
+static GLuint64
+get_texture_handle(struct gl_context *ctx, struct gl_texture_object *texObj,
+                   struct gl_sampler_object *sampObj)
+{
+   bool separate_sampler = &texObj->Sampler != sampObj;
+   struct gl_texture_handle_object *texHandleObj;
+   GLuint64 handle;
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The handle for each texture or texture/sampler pair is unique; the same
+    *  handle will be returned if GetTextureHandleARB is called multiple times
+    *  for the same texture or if GetTextureSamplerHandleARB is called multiple
+    *  times for the same texture/sampler pair."
+    */
+   mtx_lock(&ctx->Shared->HandlesMutex);
+   texHandleObj = find_texhandleobj(texObj, separate_sampler ? sampObj : NULL);
+   if (texHandleObj) {
+      mtx_unlock(&ctx->Shared->HandlesMutex);
+      return texHandleObj->handle;
+   }
+
+   /* Request a new texture handle from the driver. */
+   handle = ctx->Driver.NewTextureHandle(ctx, texObj, sampObj);
+   if (!handle) {
+      mtx_unlock(&ctx->Shared->HandlesMutex);
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexture*HandleARB()");
+      return 0;
+   }
+
+   /* Store the handle into the texture object. */
+   texHandleObj = u_vector_add(&texObj->SamplerHandles);
+   texHandleObj->texObj = texObj;
+   texHandleObj->sampObj = separate_sampler ? sampObj : NULL;
+   texHandleObj->handle = handle;
+
+   if (&texObj->Sampler != sampObj) {
+      /* Store a reference to the handle into the separate sampler object. */
+      struct gl_texture_handle_object **sampHandleObj;
+
+      sampHandleObj = u_vector_add(&sampObj->Handles);
+      *sampHandleObj = texHandleObj;
+   }
+
+   /* When referenced by one or more handles, texture objects are immutable. */
+   texObj->HandleAllocated = true;
+   if (texObj->Target == GL_TEXTURE_BUFFER)
+      texObj->BufferObject->HandleAllocated = true;
+   sampObj->HandleAllocated = true;
+
+   /* Store the handle in the shared state for all contexts. */
+   hash_table_insert(ctx->Shared->TextureHandles, handle, texHandleObj);
+   mtx_unlock(&ctx->Shared->HandlesMutex);
+
+   return (GLuint64)handle;
+}
+
+static struct gl_image_handle_object *
+find_imghandleobj(struct gl_texture_object *texObj, GLint level,
+                  GLboolean layered, GLint layer, GLenum format)
+{
+   struct gl_image_handle_object *imgHandleObj;
+
+   u_vector_foreach(imgHandleObj, &texObj->ImageHandles) {
+      struct gl_image_unit *u = &imgHandleObj->imgObj;
+
+      if (u->Level == level && u->Layered == layered &&
+          u->Layer == layer && u->Format == format)
+         return imgHandleObj;
+   }
+   return NULL;
+}
+
+static GLuint64
+get_image_handle(struct gl_context *ctx, struct gl_texture_object *texObj,
+                 GLint level, GLboolean layered, GLint layer, GLenum format)
+{
+   struct gl_image_handle_object *imgHandleObj;
+   struct gl_image_unit imgObj;
+   GLuint64 handle;
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The handle returned for each combination of <texture>, <level>,
+    * <layered>, <layer>, and <format> is unique; the same handle will be
+    * returned if GetImageHandleARB is called multiple times with the same
+    * parameters."
+    */
+   mtx_lock(&ctx->Shared->HandlesMutex);
+   imgHandleObj = find_imghandleobj(texObj, level, layered, layer, format);
+   if (imgHandleObj) {
+      mtx_unlock(&ctx->Shared->HandlesMutex);
+      return imgHandleObj->handle;
+   }
+
+   imgObj.TexObj = texObj; /* weak reference */
+   imgObj.Level = level;
+   imgObj.Access = GL_READ_WRITE;
+   imgObj.Format = format;
+   imgObj._ActualFormat = _mesa_get_shader_image_format(format);
+
+   if (_mesa_tex_target_is_layered(texObj->Target)) {
+      imgObj.Layered = layered;
+      imgObj.Layer = layer;
+      imgObj._Layer = (imgObj.Layered ? 0 : imgObj.Layer);
+   } else {
+      imgObj.Layered = GL_FALSE;
+      imgObj.Layer = 0;
+   }
+
+   /* Request a new image handle from the driver. */
+   handle = ctx->Driver.NewImageHandle(ctx, &imgObj);
+   if (!handle) {
+      mtx_unlock(&ctx->Shared->HandlesMutex);
+      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetImageHandleARB()");
+      return 0;
+   }
+
+   /* Store the handle into the texture object. */
+   imgHandleObj = u_vector_add(&texObj->ImageHandles);
+   memcpy(&imgHandleObj->imgObj, &imgObj, sizeof(struct gl_image_unit));
+   imgHandleObj->handle = handle;
+
+   /* When referenced by one or more handles, texture objects are immutable. */
+   texObj->HandleAllocated = true;
+   if (texObj->Target == GL_TEXTURE_BUFFER)
+      texObj->BufferObject->HandleAllocated = true;
+   texObj->Sampler.HandleAllocated = true;
+
+   /* Store the handle in the shared state for all contexts. */
+   hash_table_insert(ctx->Shared->ImageHandles, handle, imgHandleObj);
+   mtx_unlock(&ctx->Shared->HandlesMutex);
+
+   return (GLuint64)handle;
+}
+
+/**
+ * Init/free resident handles per-context.
+ */
+void
+_mesa_init_resident_handles(struct gl_context *ctx)
+{
+#if !defined(MESA_ARCH_X86_64)
+   ctx->ResidentTextureHandles =
+      _mesa_hash_table_create(NULL, key_hash, key_equals);
+   ctx->ResidentImageHandles =
+      _mesa_hash_table_create(NULL, key_hash, key_equals);
+#else
+   ctx->ResidentTextureHandles =
+      _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+                              _mesa_key_pointer_equal);
+   ctx->ResidentImageHandles =
+      _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+                              _mesa_key_pointer_equal);
+#endif
+}
+
+void
+_mesa_free_resident_handles(struct gl_context *ctx)
+{
+   _mesa_hash_table_destroy(ctx->ResidentTextureHandles, NULL);
+   _mesa_hash_table_destroy(ctx->ResidentImageHandles, NULL);
+}
+
+/**
+ * Init/free shared handles.
+ */
+void
+_mesa_init_shared_handles(struct gl_shared_state *shared)
+{
+#if !defined(MESA_ARCH_X86_64)
+   shared->TextureHandles =
+      _mesa_hash_table_create(NULL, key_hash, key_equals);
+   shared->ImageHandles =
+      _mesa_hash_table_create(NULL, key_hash, key_equals);
+#else
+   shared->TextureHandles =
+      _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+                              _mesa_key_pointer_equal);
+   shared->ImageHandles =
+      _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+                              _mesa_key_pointer_equal);
+#endif
+   mtx_init(&shared->HandlesMutex, mtx_recursive);
+}
+
+void
+_mesa_free_shared_handles(struct gl_shared_state *shared)
+{
+   _mesa_hash_table_destroy(shared->TextureHandles, NULL);
+   _mesa_hash_table_destroy(shared->ImageHandles, NULL);
+   mtx_destroy(&shared->HandlesMutex);
+}
+
+/**
+ * Init/free texture/image handles per-texture object.
+ */
+void
+_mesa_init_texture_handles(struct gl_texture_object *texObj)
+{
+   uint32_t element_size;
+
+   element_size =
+      util_next_power_of_two(sizeof(struct gl_texture_handle_object));
+   u_vector_init(&texObj->SamplerHandles, element_size, 2 * element_size);
+
+   element_size =
+      util_next_power_of_two(sizeof(struct gl_image_handle_object));
+   u_vector_init(&texObj->ImageHandles, element_size, 2 * element_size);
+}
+
+void
+_mesa_make_texture_handles_non_resident(struct gl_context *ctx,
+                                        struct gl_texture_object *texObj)
+{
+   struct gl_texture_handle_object *texHandleObj;
+   struct gl_image_handle_object *imgHandleObj;
+
+   mtx_lock(&ctx->Shared->HandlesMutex);
+
+   u_vector_foreach(texHandleObj, &texObj->SamplerHandles) {
+      if (is_texture_handle_resident(ctx, texHandleObj->handle))
+         make_texture_handle_resident(ctx, texHandleObj, false);
+   }
+
+   u_vector_foreach(imgHandleObj, &texObj->ImageHandles) {
+      if (is_image_handle_resident(ctx, imgHandleObj->handle))
+         make_image_handle_resident(ctx, imgHandleObj, GL_READ_ONLY, false);
+   }
+
+   mtx_unlock(&ctx->Shared->HandlesMutex);
+}
+
+void
+_mesa_delete_texture_handles(struct gl_context *ctx,
+                             struct gl_texture_object *texObj)
+{
+   struct gl_texture_handle_object *texHandleObj;
+   struct gl_image_handle_object *imgHandleObj;
+
+   /* Texture handles */
+   u_vector_foreach(texHandleObj, &texObj->SamplerHandles)
+      delete_texture_handle(ctx, texHandleObj->handle);
+   u_vector_finish(&texObj->SamplerHandles);
+
+   /* Image handles */
+   u_vector_foreach(imgHandleObj, &texObj->ImageHandles)
+      delete_image_handle(ctx, imgHandleObj->handle);
+   u_vector_finish(&texObj->ImageHandles);
+}
+
+/**
+ * Init/free texture handles per-sampler object.
+ */
+void
+_mesa_init_sampler_handles(struct gl_sampler_object *sampObj)
+{
+   uint32_t element_size;
+
+   element_size =
+      util_next_power_of_two(sizeof(struct gl_texture_handle_object));
+   u_vector_init(&sampObj->Handles, element_size, 2 * element_size);
+}
+
+void
+_mesa_delete_sampler_handles(struct gl_context *ctx,
+                             struct gl_sampler_object *sampObj)
+{
+   struct gl_texture_handle_object **sampHandleObj;
+
+   u_vector_foreach(sampHandleObj, &sampObj->Handles)
+      delete_texture_handle(ctx, (*sampHandleObj)->handle);
+   u_vector_finish(&sampObj->Handles);
+}
+
+static GLboolean
+is_sampler_border_color_valid(struct gl_sampler_object *samp)
+{
+   static const GLfloat valid_float_border_colors[4][4] = {
+      { 0.0, 0.0, 0.0, 0.0 },
+      { 0.0, 0.0, 0.0, 1.0 },
+      { 1.0, 1.0, 1.0, 0.0 },
+      { 1.0, 1.0, 1.0, 1.0 },
+   };
+   static const GLint valid_integer_border_colors[4][4] = {
+      { 0, 0, 0, 0 },
+      { 0, 0, 0, 1 },
+      { 1, 1, 1, 0 },
+      { 1, 1, 1, 1 },
+   };
+   size_t size = sizeof(samp->BorderColor.ui);
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated if the border color (taken from
+    *  the embedded sampler for GetTextureHandleARB or from the <sampler> for
+    *  GetTextureSamplerHandleARB) is not one of the following allowed values.
+    *  If the texture's base internal format is signed or unsigned integer,
+    *  allowed values are (0,0,0,0), (0,0,0,1), (1,1,1,0), and (1,1,1,1). If
+    *  the base internal format is not integer, allowed values are
+    *  (0.0,0.0,0.0,0.0), (0.0,0.0,0.0,1.0), (1.0,1.0,1.0,0.0), and
+    *  (1.0,1.0,1.0,1.0)."
+    */
+   if (!memcmp(samp->BorderColor.f, valid_float_border_colors[0], size) ||
+       !memcmp(samp->BorderColor.f, valid_float_border_colors[1], size) ||
+       !memcmp(samp->BorderColor.f, valid_float_border_colors[2], size) ||
+       !memcmp(samp->BorderColor.f, valid_float_border_colors[3], size))
+      return GL_TRUE;
+
+   if (!memcmp(samp->BorderColor.ui, valid_integer_border_colors[0], size) ||
+       !memcmp(samp->BorderColor.ui, valid_integer_border_colors[1], size) ||
+       !memcmp(samp->BorderColor.ui, valid_integer_border_colors[2], size) ||
+       !memcmp(samp->BorderColor.ui, valid_integer_border_colors[3], size))
+      return GL_TRUE;
+
+   return GL_FALSE;
+}
+
 GLuint64 GLAPIENTRY
 _mesa_GetTextureHandleARB(GLuint texture)
 {
-   return 0;
+   struct gl_texture_object *texObj = NULL;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetTextureHandleARB(unsupported)");
+      return 0;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_VALUE is generated by GetTextureHandleARB or
+    *  GetTextureSamplerHandleARB if <texture> is zero or not the name of an
+    *  existing texture object."
+    */
+   if (texture > 0)
+      texObj = _mesa_lookup_texture(ctx, texture);
+
+   if (!texObj) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetTextureHandleARB(texture)");
+      return 0;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated by GetTextureHandleARB or
+    *  GetTextureSamplerHandleARB if the texture object specified by <texture>
+    *  is not complete."
+    */
+   if (!_mesa_is_texture_complete(texObj, &texObj->Sampler)) {
+      _mesa_test_texobj_completeness(ctx, texObj);
+      if (!_mesa_is_texture_complete(texObj, &texObj->Sampler)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetTextureHandleARB(incomplete texture)");
+         return 0;
+      }
+   }
+
+   if (!is_sampler_border_color_valid(&texObj->Sampler)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetTextureHandleARB(invalid border color)");
+      return 0;
+   }
+
+   return get_texture_handle(ctx, texObj, &texObj->Sampler);
 }
 
 GLuint64 GLAPIENTRY
 _mesa_GetTextureSamplerHandleARB(GLuint texture, GLuint sampler)
 {
-   return 0;
+   struct gl_texture_object *texObj = NULL;
+   struct gl_sampler_object *sampObj;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetTextureSamplerHandleARB(unsupported)");
+      return 0;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_VALUE is generated by GetTextureHandleARB or
+    *  GetTextureSamplerHandleARB if <texture> is zero or not the name of an
+    *  existing texture object."
+    */
+   if (texture > 0)
+      texObj = _mesa_lookup_texture(ctx, texture);
+
+   if (!texObj) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glGetTextureSamplerHandleARB(texture)");
+      return 0;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_VALUE is generated by GetTextureSamplerHandleARB if
+    *  <sampler> is zero or is not the name of an existing sampler object."
+    */
+   sampObj = _mesa_lookup_samplerobj(ctx, sampler);
+   if (!sampObj) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                  "glGetTextureSamplerHandleARB(sampler)");
+      return 0;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated by GetTextureHandleARB or
+    *  GetTextureSamplerHandleARB if the texture object specified by <texture>
+    *  is not complete."
+    */
+   if (!_mesa_is_texture_complete(texObj, sampObj)) {
+      _mesa_test_texobj_completeness(ctx, texObj);
+      if (!_mesa_is_texture_complete(texObj, sampObj)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetTextureSamplerHandleARB(incomplete texture)");
+         return 0;
+      }
+   }
+
+   if (!is_sampler_border_color_valid(sampObj)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetTextureSamplerHandleARB(invalid border color)");
+      return 0;
+   }
+
+   return get_texture_handle(ctx, texObj, sampObj);
 }
 
 void GLAPIENTRY
 _mesa_MakeTextureHandleResidentARB(GLuint64 handle)
 {
+   struct gl_texture_handle_object *texHandleObj;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeTextureHandleResidentARB(unsupported)");
+      return;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated by MakeTextureHandleResidentARB
+    *  if <handle> is not a valid texture handle, or if <handle> is already
+    *  resident in the current GL context."
+    */
+   texHandleObj = lookup_texture_handle(ctx, handle);
+   if (!texHandleObj) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeTextureHandleResidentARB(handle)");
+      return;
+   }
+
+   if (is_texture_handle_resident(ctx, handle)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeTextureHandleResidentARB(already resident)");
+      return;
+   }
+
+   make_texture_handle_resident(ctx, texHandleObj, true);
 }
 
 void GLAPIENTRY
 _mesa_MakeTextureHandleNonResidentARB(GLuint64 handle)
 {
+   struct gl_texture_handle_object *texHandleObj;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeTextureHandleNonResidentARB(unsupported)");
+      return;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated by
+    *  MakeTextureHandleNonResidentARB if <handle> is not a valid texture
+    *  handle, or if <handle> is not resident in the current GL context."
+    */
+   texHandleObj = lookup_texture_handle(ctx, handle);
+   if (!texHandleObj) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeTextureHandleNonResidentARB(handle)");
+      return;
+   }
+
+   if (!is_texture_handle_resident(ctx, handle)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeTextureHandleNonResidentARB(not resident)");
+      return;
+   }
+
+   make_texture_handle_resident(ctx, texHandleObj, false);
 }
 
 GLuint64 GLAPIENTRY
 _mesa_GetImageHandleARB(GLuint texture, GLint level, GLboolean layered,
                         GLint layer, GLenum format)
 {
-   return 0;
+   struct gl_texture_object *texObj = NULL;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx) ||
+       !_mesa_has_ARB_shader_image_load_store(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetImageHandleARB(unsupported)");
+      return 0;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_VALUE is generated by GetImageHandleARB if <texture>
+    *  is zero or not the name of an existing texture object, if the image for
+    *  <level> does not existing in <texture>, or if <layered> is FALSE and
+    *  <layer> is greater than or equal to the number of layers in the image at
+    *  <level>."
+    */
+   if (texture > 0)
+      texObj = _mesa_lookup_texture(ctx, texture);
+
+   if (!texObj) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetImageHandleARB(texture)");
+      return 0;
+   }
+
+   if (level < 0 || level >= _mesa_max_texture_levels(ctx, texObj->Target)) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetImageHandleARB(level)");
+      return 0;
+   }
+
+   if (!layered && layer > _mesa_get_texture_layers(texObj, level)) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetImageHandleARB(layer)");
+      return 0;
+   }
+
+   if (!_mesa_is_shader_image_format_supported(ctx, format)) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetImageHandleARB(format)");
+      return 0;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated by GetImageHandleARB if the
+    *  texture object <texture> is not complete or if <layered> is TRUE and
+    *  <texture> is not a three-dimensional, one-dimensional array, two
+    *  dimensional array, cube map, or cube map array texture."
+    */
+   if (!_mesa_is_texture_complete(texObj, &texObj->Sampler)) {
+      _mesa_test_texobj_completeness(ctx, texObj);
+      if (!_mesa_is_texture_complete(texObj, &texObj->Sampler)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glGetImageHandleARB(incomplete texture)");
+         return 0;
+      }
+   }
+
+   if (layered && !_mesa_tex_target_is_layered(texObj->Target)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glGetImageHandleARB(not layered)");
+      return 0;
+   }
+
+   return get_image_handle(ctx, texObj, level, layered, layer, format);
 }
 
 void GLAPIENTRY
 _mesa_MakeImageHandleResidentARB(GLuint64 handle, GLenum access)
 {
+   struct gl_image_handle_object *imgHandleObj;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx) ||
+       !_mesa_has_ARB_shader_image_load_store(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeImageHandleResidentARB(unsupported)");
+      return;
+   }
+
+   if (access != GL_READ_ONLY &&
+       access != GL_WRITE_ONLY &&
+       access != GL_READ_WRITE) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "glMakeImageHandleResidentARB(access)");
+      return;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated by MakeImageHandleResidentARB
+    *  if <handle> is not a valid image handle, or if <handle> is already
+    *  resident in the current GL context."
+    */
+   imgHandleObj = lookup_image_handle(ctx, handle);
+   if (!imgHandleObj) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeImageHandleResidentARB(handle)");
+      return;
+   }
+
+   if (is_image_handle_resident(ctx, handle)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeImageHandleResidentARB(already resident)");
+      return;
+   }
+
+   make_image_handle_resident(ctx, imgHandleObj, access, true);
 }
 
 void GLAPIENTRY
 _mesa_MakeImageHandleNonResidentARB(GLuint64 handle)
 {
+   struct gl_image_handle_object *imgHandleObj;
+
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx) ||
+       !_mesa_has_ARB_shader_image_load_store(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeImageHandleNonResidentARB(unsupported)");
+      return;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION is generated by
+    *  MakeImageHandleNonResidentARB if <handle> is not a valid image handle,
+    *  or if <handle> is not resident in the current GL context."
+    */
+   imgHandleObj = lookup_image_handle(ctx, handle);
+   if (!imgHandleObj) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeImageHandleNonResidentARB(handle)");
+      return;
+   }
+
+   if (!is_image_handle_resident(ctx, handle)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glMakeImageHandleNonResidentARB(not resident)");
+      return;
+   }
+
+   make_image_handle_resident(ctx, imgHandleObj, GL_READ_ONLY, false);
 }
 
 GLboolean GLAPIENTRY
 _mesa_IsTextureHandleResidentARB(GLuint64 handle)
 {
-   return GL_FALSE;
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glIsTextureHandleResidentARB(unsupported)");
+      return GL_FALSE;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION will be generated by
+    *  IsTextureHandleResidentARB and IsImageHandleResidentARB if <handle> is
+    *  not a valid texture or image handle, respectively."
+    */
+   if (!lookup_texture_handle(ctx, handle)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glIsTextureHandleResidentARB(handle)");
+      return GL_FALSE;
+   }
+
+   return is_texture_handle_resident(ctx, handle);
 }
 
 GLboolean GLAPIENTRY
 _mesa_IsImageHandleResidentARB(GLuint64 handle)
 {
-   return GL_FALSE;
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (!_mesa_has_ARB_bindless_texture(ctx) ||
+       !_mesa_has_ARB_shader_image_load_store(ctx)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glIsImageHandleResidentARB(unsupported)");
+      return GL_FALSE;
+   }
+
+   /* The ARB_bindless_texture spec says:
+    *
+    * "The error INVALID_OPERATION will be generated by
+    *  IsTextureHandleResidentARB and IsImageHandleResidentARB if <handle> is
+    *  not a valid texture or image handle, respectively."
+    */
+   if (!lookup_image_handle(ctx, handle)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glIsImageHandleResidentARB(handle)");
+      return GL_FALSE;
+   }
+
+   return is_image_handle_resident(ctx, handle);
 }
diff --git a/src/mesa/main/texturebindless.h b/src/mesa/main/texturebindless.h
index 88b84ce275..d584f5cc0c 100644
--- a/src/mesa/main/texturebindless.h
+++ b/src/mesa/main/texturebindless.h
@@ -31,6 +31,38 @@ extern "C" {
 #endif
 
 /**
+ * \name Internal functions
+ */
+/*@{*/
+
+void
+_mesa_init_resident_handles(struct gl_context *ctx);
+void
+_mesa_free_resident_handles(struct gl_context *ctx);
+
+void
+_mesa_init_shared_handles(struct gl_shared_state *shared);
+void
+_mesa_free_shared_handles(struct gl_shared_state *shared);
+
+void
+_mesa_init_texture_handles(struct gl_texture_object *texObj);
+void
+_mesa_make_texture_handles_non_resident(struct gl_context *ctx,
+                                        struct gl_texture_object *texObj);
+void
+_mesa_delete_texture_handles(struct gl_context *ctx,
+                             struct gl_texture_object *texObj);
+
+void
+_mesa_init_sampler_handles(struct gl_sampler_object *sampObj);
+void
+_mesa_delete_sampler_handles(struct gl_context *ctx,
+                             struct gl_sampler_object *sampObj);
+
+/*@}*/
+
+/**
  * \name API functions
  */
 /*@{*/
-- 
2.13.0



More information about the mesa-dev mailing list