[Mesa-dev] [RFC PATCH 02/65] mesa: implement ARB_bindless_texture
Samuel Pitoiset
samuel.pitoiset at gmail.com
Fri May 19 16:52:07 UTC 2017
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 | 34 ++
src/mesa/main/samplerobj.c | 6 +
src/mesa/main/shared.c | 12 +
src/mesa/main/texobj.c | 12 +
src/mesa/main/texturebindless.c | 827 +++++++++++++++++++++++++++++++++++++++-
src/mesa/main/texturebindless.h | 28 ++
8 files changed, 934 insertions(+), 5 deletions(-)
diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 3570f94f5a..5321886a95 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 efc6920254..70865b373d 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -987,6 +987,9 @@ 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 */
+ bool HandleAllocated; /**< GL_ARB_bindless_texture */
+
+ struct hash_table *Handles;
};
@@ -1034,6 +1037,8 @@ struct gl_texture_object
GLuint NumLevels; /**< GL_ARB_texture_view */
GLuint NumLayers; /**< GL_ARB_texture_view */
+ GLboolean HandleAllocated; /**< GL_ARB_bindless_texture */
+
/** Actual texture images, indexed by [cube face] and [mipmap level] */
struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS];
@@ -1051,6 +1056,10 @@ struct gl_texture_object
/** GL_ARB_shader_image_load_store */
GLenum ImageFormatCompatibilityType;
+
+ /** GL_ARB_bindless_texture */
+ struct hash_table *SamplerHandles;
+ struct hash_table *ImageHandles;
};
@@ -1390,6 +1399,7 @@ struct gl_buffer_object
GLboolean Written; /**< Ever written to? (for debugging) */
GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
GLboolean Immutable; /**< GL_ARB_buffer_storage */
+ GLboolean HandleAllocated; /**< GL_ARB_bindless_texture */
gl_buffer_usage UsageHistory; /**< How has this buffer been used so far? */
/** Counters used for buffer usage warnings */
@@ -3203,6 +3213,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
*
@@ -4488,6 +4503,17 @@ struct gl_subroutine_index_binding
GLuint *IndexPtr;
};
+struct gl_texture_handle_object
+{
+ struct gl_texture_object *texObj;
+ struct gl_sampler_object *sampObj;
+};
+
+struct gl_image_handle_object
+{
+ struct gl_image_unit imgObj;
+};
+
/**
* Mesa rendering context.
*
@@ -4842,6 +4868,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..b188287a08 100644
--- a/src/mesa/main/shared.c
+++ b/src/mesa/main/shared.c
@@ -84,6 +84,13 @@ _mesa_alloc_shared_state(struct gl_context *ctx)
/* GL_ARB_sampler_objects */
shared->SamplerObjects = _mesa_NewHashTable();
+ /* GL_ARB_bindless_texture */
+ 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);
+ mtx_init(&shared->HandlesMutex, mtx_recursive);
+
/* Allocate the default buffer object */
shared->NullBufferObj = ctx->Driver.NewBufferObject(ctx, 0);
@@ -373,6 +380,11 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared)
_mesa_HashDeleteAll(shared->TexObjects, delete_texture_cb, ctx);
_mesa_DeleteHashTable(shared->TexObjects);
+ /* Bindless texture/image handles */
+ _mesa_hash_table_destroy(shared->TextureHandles, NULL);
+ _mesa_hash_table_destroy(shared->ImageHandles, NULL);
+ mtx_destroy(&shared->HandlesMutex);
+
mtx_destroy(&shared->Mutex);
mtx_destroy(&shared->TexMutex);
diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c
index 868e4eb7a2..13a24f6deb 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,10 @@ _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..0c6f9c3fc9 100644
--- a/src/mesa/main/texturebindless.c
+++ b/src/mesa/main/texturebindless.c
@@ -29,57 +29,874 @@
#include "mtypes.h"
#include "texobj.h"
#include "texturebindless.h"
+#include "shaderimage.h"
+#include "teximage.h"
+#include "hash.h"
#include "util/set.h"
#include "util/hash_table.h"
+/**
+ * Return the gl_texture_handle_object for a given 64bit 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 = _mesa_hash_table_search(ctx->Shared->TextureHandles, (void *)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 64bit 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 = _mesa_hash_table_search(ctx->Shared->ImageHandles, (void *)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;
+
+ mtx_lock(&ctx->Shared->HandlesMutex);
+ entry = _mesa_hash_table_search(ctx->Shared->TextureHandles, (void *)id);
+ _mesa_hash_table_remove(ctx->Shared->TextureHandles, entry);
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+}
+
+/**
+ * Delete an image handle in the shared state.
+ */
+static void
+delete_image_handle(struct gl_context *ctx, GLuint64 id)
+{
+ struct hash_entry *entry;
+
+ mtx_lock(&ctx->Shared->HandlesMutex);
+ entry = _mesa_hash_table_search(ctx->Shared->ImageHandles, (void *)id);
+ _mesa_hash_table_remove(ctx->Shared->ImageHandles, entry);
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+}
+
+/**
+ * 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 _mesa_hash_table_search(ctx->ResidentTextureHandles,
+ (void *)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 _mesa_hash_table_search(ctx->ResidentImageHandles,
+ (void *)handle) != NULL;
+}
+
+/**
+ * Set 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 *handleObj,
+ GLuint64 handle, bool resident)
+{
+ if (resident) {
+ struct gl_sampler_object *sampObj = NULL;
+ struct gl_texture_object *texObj = NULL;
+
+ _mesa_hash_table_insert(ctx->ResidentTextureHandles,
+ (void *)handle, handleObj);
+
+ 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, handleObj->texObj);
+ if (handleObj->sampObj)
+ _mesa_reference_sampler_object(ctx, &sampObj, handleObj->sampObj);
+ } else {
+ struct hash_entry *entry;
+
+ entry = _mesa_hash_table_search(ctx->ResidentTextureHandles,
+ (void *)handle);
+ _mesa_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(&handleObj->texObj, NULL);
+ if (handleObj->sampObj)
+ _mesa_reference_sampler_object(ctx, &handleObj->sampObj, NULL);
+ }
+}
+
+/**
+ * Set 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 *handleObj,
+ GLuint64 handle, GLenum access, bool resident)
+{
+ if (resident) {
+ struct gl_texture_object *texObj = NULL;
+
+ _mesa_hash_table_insert(ctx->ResidentImageHandles,
+ (void *)handle, handleObj);
+
+ 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, handleObj->imgObj.TexObj);
+ } else {
+ struct hash_entry *entry;
+
+ entry = _mesa_hash_table_search(ctx->ResidentImageHandles,
+ (void *)handle);
+ _mesa_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(&handleObj->imgObj.TexObj, NULL);
+ }
+}
+
+static GLuint64
+get_texture_handle(struct gl_context *ctx, struct gl_texture_object *texObj,
+ struct gl_sampler_object *sampObj)
+{
+ struct gl_texture_handle_object *handleObj;
+ struct hash_entry *entry;
+ GLuint64 handle;
+
+ handleObj = CALLOC_STRUCT(gl_texture_handle_object);
+ if (!handleObj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexture*HandleARB()");
+ return 0;
+ }
+
+ handleObj->texObj = texObj;
+ if (&texObj->Sampler != sampObj)
+ handleObj->sampObj = sampObj;
+
+ /* 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);
+ entry = _mesa_hash_table_search(texObj->SamplerHandles, handleObj);
+ if (entry) {
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+ free(handleObj);
+ return (uint64_t)entry->data;
+ }
+
+ /* Ask the driver for a new handle and store it. */
+ handle = ctx->Driver.NewTextureHandle(ctx, texObj, sampObj);
+ if (!handle) {
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+ free(handleObj);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexture*HandleARB()");
+ return 0;
+ }
+
+ _mesa_hash_table_insert(texObj->SamplerHandles, handleObj, (void *)handle);
+
+ if (&texObj->Sampler != sampObj) {
+ _mesa_hash_table_insert(sampObj->Handles, handleObj,
+ (void *)handle);
+ }
+
+ /* When referenced by one or more handles, texture objects are immutable. */
+ texObj->HandleAllocated = true;
+ sampObj->HandleAllocated = true;
+ if (texObj->Target == GL_TEXTURE_BUFFER)
+ texObj->BufferObject->HandleAllocated = true;
+
+ /* Store the handle in the shared state for all contexts. */
+ _mesa_hash_table_insert(ctx->Shared->TextureHandles,
+ (void *)handle, handleObj);
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+
+ return (GLuint64)handle;
+}
+
+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 *handleObj;
+ struct gl_image_unit *imgObj;
+ struct hash_entry *entry;
+ GLuint64 handle;
+
+ handleObj = CALLOC_STRUCT(gl_image_handle_object);
+ if (!handleObj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetImageHandleARB()");
+ return 0;
+ }
+
+ imgObj = &handleObj->imgObj;
+ 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;
+ }
+
+ /* 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);
+ entry = _mesa_hash_table_search(texObj->ImageHandles, handleObj);
+ if (entry) {
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+ free(handleObj);
+ return (uint64_t)entry->data;
+ }
+
+ /* Ask the driver for a new handle and store it. */
+ handle = ctx->Driver.NewImageHandle(ctx, &handleObj->imgObj);
+ if (!handle) {
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+ free(handleObj);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetImageHandleARB()");
+ return 0;
+ }
+
+ _mesa_hash_table_insert(texObj->ImageHandles, handleObj, (void *)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. */
+ _mesa_hash_table_insert(ctx->Shared->ImageHandles,
+ (void *)handle, handleObj);
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+
+ return (GLuint64)handle;
+}
+
+void
+_mesa_init_resident_handles(struct gl_context *ctx)
+{
+ 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);
+}
+
+void
+_mesa_free_resident_handles(struct gl_context *ctx)
+{
+ _mesa_hash_table_destroy(ctx->ResidentTextureHandles, NULL);
+ _mesa_hash_table_destroy(ctx->ResidentImageHandles, NULL);
+}
+
+static uint32_t
+texture_handle_key_hash(const void *key)
+{
+ return _mesa_hash_data(key, sizeof(struct gl_texture_handle_object));
+}
+
+static bool
+texture_handle_key_equals(const void *a, const void *b)
+{
+ struct gl_texture_handle_object *aa = (struct gl_texture_handle_object *)a;
+ struct gl_texture_handle_object *bb = (struct gl_texture_handle_object *)b;
+
+ return !memcmp(aa, bb, sizeof(struct gl_texture_handle_object));
+}
+
+static uint32_t
+image_handle_key_hash(const void *key)
+{
+ return _mesa_hash_data(key, sizeof(struct gl_image_handle_object));
+}
+
+static bool
+image_handle_key_equals(const void *a, const void *b)
+{
+ struct gl_image_handle_object *aa = (struct gl_image_handle_object *)a;
+ struct gl_image_handle_object *bb = (struct gl_image_handle_object *)b;
+
+ return !memcmp(aa, bb, sizeof(struct gl_image_handle_object));
+}
+
+void
+_mesa_init_texture_handles(struct gl_texture_object *texObj)
+{
+ texObj->SamplerHandles =
+ _mesa_hash_table_create(NULL, texture_handle_key_hash,
+ texture_handle_key_equals);
+ texObj->ImageHandles =
+ _mesa_hash_table_create(NULL, image_handle_key_hash,
+ image_handle_key_equals);
+}
+
+void
+_mesa_make_texture_handles_non_resident(struct gl_context *ctx,
+ struct gl_texture_object *texObj)
+{
+ struct hash_entry *entry;
+ GLuint64 handle;
+
+ mtx_lock(&ctx->Shared->HandlesMutex);
+
+ hash_table_foreach(texObj->SamplerHandles, entry) {
+ struct gl_texture_handle_object *handleObj =
+ (struct gl_texture_handle_object *)entry->key;
+
+ handle = (uint64_t)entry->data;
+ if (is_texture_handle_resident(ctx, handle))
+ make_texture_handle_resident(ctx, handleObj, handle, false);
+ }
+
+ hash_table_foreach(texObj->ImageHandles, entry) {
+ struct gl_image_handle_object *handleObj =
+ (struct gl_image_handle_object *)entry->key;
+
+ handle = (uint64_t)entry->data;
+ if (is_image_handle_resident(ctx, handle))
+ make_image_handle_resident(ctx, handleObj, handle, GL_READ_ONLY, false);
+ }
+
+ mtx_unlock(&ctx->Shared->HandlesMutex);
+}
+
+void
+_mesa_delete_texture_handles(struct gl_context *ctx,
+ struct gl_texture_object *texObj)
+{
+ struct hash_entry *entry;
+
+ hash_table_foreach(texObj->SamplerHandles, entry) {
+ struct gl_texture_handle_object *handleObj =
+ (struct gl_texture_handle_object *)entry->key;
+ GLuint64 handle = (GLuint64)entry->data;
+
+ ctx->Driver.DeleteTextureHandle(ctx, handle);
+
+ delete_texture_handle(ctx, handle);
+ free(handleObj);
+ }
+
+ hash_table_foreach(texObj->ImageHandles, entry) {
+ struct gl_image_handle_object *handleObj =
+ (struct gl_image_handle_object *)entry->key;
+ GLuint64 handle = (GLuint64)entry->data;
+
+ ctx->Driver.DeleteImageHandle(ctx, handle);
+
+ delete_image_handle(ctx, handle);
+ free(handleObj);
+ }
+
+ _mesa_hash_table_destroy(texObj->SamplerHandles, NULL);
+ _mesa_hash_table_destroy(texObj->ImageHandles, NULL);
+}
+
+void
+_mesa_init_sampler_handles(struct gl_sampler_object *sampObj)
+{
+ sampObj->Handles = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+}
+
+void
+_mesa_delete_sampler_handles(struct gl_context *ctx,
+ struct gl_sampler_object *sampObj)
+{
+ struct hash_entry *entry;
+
+ hash_table_foreach(sampObj->Handles, entry) {
+ GLuint64 handle = (GLuint64)entry->data;
+
+ ctx->Driver.DeleteTextureHandle(ctx, handle);
+
+ delete_texture_handle(ctx, handle);
+ }
+
+ _mesa_hash_table_destroy(sampObj->Handles, NULL);
+}
+
+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 *handleObj;
+
+ 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."
+ */
+ handleObj = lookup_texture_handle(ctx, handle);
+ if (!handleObj) {
+ _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, handleObj, handle, true);
}
void GLAPIENTRY
_mesa_MakeTextureHandleNonResidentARB(GLuint64 handle)
{
+ struct gl_texture_handle_object *handleObj;
+
+ 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."
+ */
+ handleObj = lookup_texture_handle(ctx, handle);
+ if (!handleObj) {
+ _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, handleObj, handle, 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 *handleObj;
+
+ 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."
+ */
+ handleObj = lookup_image_handle(ctx, handle);
+ if (!handleObj) {
+ _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, handleObj, handle, access, true);
}
void GLAPIENTRY
_mesa_MakeImageHandleNonResidentARB(GLuint64 handle)
{
+ struct gl_image_handle_object *handleObj;
+
+ 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."
+ */
+ handleObj = lookup_image_handle(ctx, handle);
+ if (!handleObj) {
+ _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, handleObj, handle, 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..bdee74121e 100644
--- a/src/mesa/main/texturebindless.h
+++ b/src/mesa/main/texturebindless.h
@@ -31,6 +31,34 @@ 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_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