[Mesa-dev] [PATCH v4 05/63] mesa: implement ARB_bindless_texture
Nicolai Hähnle
nhaehnle at gmail.com
Wed Jun 14 07:33:20 UTC 2017
Reviewed-by: Nicolai Hähnle <nicolai.haehnle at amd.com>
On 13.06.2017 19:12, Samuel Pitoiset wrote:
> v4: - use hash_table_u64 wrapper
> v3: - do not use lookup_*_handle() in delete_*_handle()
> - allocate _key on the stack for hash_table_search() wrapper
> - add assertions in make_{texture,image}_handle_resident()
> - remove useless casts in get_{texture,image}_handle
> - fix refcounting
> - use u_dynarray instead of u_vector
> - fix deleted_key
> 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 | 852 +++++++++++++++++++++++++++++++++++++++-
> src/mesa/main/texturebindless.h | 32 ++
> 8 files changed, 960 insertions(+), 7 deletions(-)
>
> diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> index 9aa6fb64b24..b801322fd02 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 29fc93f20d9..84ed57f2df0 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 21ddf57f11b..8a80f4feb45 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_dynarray.h"
>
>
> #ifdef __cplusplus
> @@ -988,6 +989,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 util_dynarray Handles;
> + bool HandleAllocated;
> };
>
>
> @@ -1052,6 +1057,11 @@ struct gl_texture_object
>
> /** GL_ARB_shader_image_load_store */
> GLenum ImageFormatCompatibilityType;
> +
> + /** GL_ARB_bindless_texture */
> + struct util_dynarray SamplerHandles;
> + struct util_dynarray ImageHandles;
> + bool HandleAllocated;
> };
>
>
> @@ -1404,6 +1414,8 @@ struct gl_buffer_object
> unsigned MinMaxCacheHitIndices;
> unsigned MinMaxCacheMissIndices;
> bool MinMaxCacheDirty;
> +
> + bool HandleAllocated; /**< GL_ARB_bindless_texture */
> };
>
>
> @@ -3212,6 +3224,11 @@ struct gl_shared_state
> /** GL_ARB_sampler_objects */
> struct _mesa_HashTable *SamplerObjects;
>
> + /* GL_ARB_bindless_texture */
> + struct hash_table_u64 *TextureHandles;
> + struct hash_table_u64 *ImageHandles;
> + mtx_t HandlesMutex; /**< For texture/image handles safety */
> +
> /**
> * Some context in this share group was affected by a GPU reset
> *
> @@ -4515,6 +4532,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.
> *
> @@ -4869,6 +4899,14 @@ struct gl_context
> GLfloat PrimitiveBoundingBox[8];
>
> struct disk_cache *Cache;
> +
> + /**
> + * \name GL_ARB_bindless_texture
> + */
> + /*@{*/
> + struct hash_table_u64 *ResidentTextureHandles;
> + struct hash_table_u64 *ResidentImageHandles;
> + /*@}*/
> };
>
> /**
> diff --git a/src/mesa/main/samplerobj.c b/src/mesa/main/samplerobj.c
> index 63beaf1abba..ee15c68b4ff 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 53448127389..6926d40570b 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 868e4eb7a27..1877262ed65 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 4d9c22d428d..26b0f58bcd2 100644
> --- a/src/mesa/main/texturebindless.c
> +++ b/src/mesa/main/texturebindless.c
> @@ -25,61 +25,899 @@
> #include "context.h"
> #include "enums.h"
> #include "imports.h"
> -#include "macros.h"
> +#include "hash.h"
> #include "mtypes.h"
> +#include "shaderimage.h"
> +#include "teximage.h"
> #include "texobj.h"
> #include "texturebindless.h"
>
> -#include "util/set.h"
> #include "util/hash_table.h"
>
> +/**
> + * 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 gl_texture_handle_object *texHandleObj;
> +
> + mtx_lock(&ctx->Shared->HandlesMutex);
> + texHandleObj = (struct gl_texture_handle_object *)
> + _mesa_hash_table_u64_search(ctx->Shared->TextureHandles, id);
> + mtx_unlock(&ctx->Shared->HandlesMutex);
> +
> + return texHandleObj;
> +}
> +
> +/**
> + * 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 gl_image_handle_object *imgHandleObj;
> +
> + mtx_lock(&ctx->Shared->HandlesMutex);
> + imgHandleObj = (struct gl_image_handle_object *)
> + _mesa_hash_table_u64_search(ctx->Shared->ImageHandles, id);
> + mtx_unlock(&ctx->Shared->HandlesMutex);
> +
> + return imgHandleObj;
> +}
> +
> +/**
> + * Delete a texture handle in the shared state.
> + */
> +static void
> +delete_texture_handle(struct gl_context *ctx, GLuint64 id)
> +{
> + mtx_lock(&ctx->Shared->HandlesMutex);
> + _mesa_hash_table_u64_remove(ctx->Shared->TextureHandles, id);
> + 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)
> +{
> + mtx_lock(&ctx->Shared->HandlesMutex);
> + _mesa_hash_table_u64_remove(ctx->Shared->ImageHandles, id);
> + 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 _mesa_hash_table_u64_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 _mesa_hash_table_u64_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)
> +{
> + struct gl_sampler_object *sampObj = NULL;
> + struct gl_texture_object *texObj = NULL;
> + GLuint64 handle = texHandleObj->handle;
> +
> + if (resident) {
> + assert(!is_texture_handle_resident(ctx, handle));
> +
> + _mesa_hash_table_u64_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 {
> + assert(is_texture_handle_resident(ctx, handle));
> +
> + _mesa_hash_table_u64_remove(ctx->ResidentTextureHandles, handle);
> +
> + ctx->Driver.MakeTextureHandleResident(ctx, handle, GL_FALSE);
> +
> + /* Unreference the texture object but keep the pointer intact, if
> + * refcount hits zero, the texture and all handles will be deleted.
> + */
> + texObj = texHandleObj->texObj;
> + _mesa_reference_texobj(&texObj, NULL);
> +
> + /* Unreference the separate sampler object but keep the pointer intact,
> + * if refcount hits zero, the sampler and all handles will be deleted.
> + */
> + if (texHandleObj->sampObj) {
> + sampObj = texHandleObj->sampObj;
> + _mesa_reference_sampler_object(ctx, &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)
> +{
> + struct gl_texture_object *texObj = NULL;
> + GLuint64 handle = imgHandleObj->handle;
> +
> + if (resident) {
> + assert(!is_image_handle_resident(ctx, handle));
> +
> + _mesa_hash_table_u64_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 {
> + assert(is_image_handle_resident(ctx, handle));
> +
> + _mesa_hash_table_u64_remove(ctx->ResidentImageHandles, handle);
> +
> + ctx->Driver.MakeImageHandleResident(ctx, handle, access, GL_FALSE);
> +
> + /* Unreference the texture object but keep the pointer intact, if
> + * refcount hits zero, the texture and all handles will be deleted.
> + */
> + texObj = imgHandleObj->imgObj.TexObj;
> + _mesa_reference_texobj(&texObj, NULL);
> + }
> +}
> +
> +static struct gl_texture_handle_object *
> +find_texhandleobj(struct gl_texture_object *texObj,
> + struct gl_sampler_object *sampObj)
> +{
> + util_dynarray_foreach(&texObj->SamplerHandles,
> + struct gl_texture_handle_object *, texHandleObj) {
> + 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;
> + }
> +
> + texHandleObj = CALLOC_STRUCT(gl_texture_handle_object);
> + if (!texHandleObj) {
> + mtx_unlock(&ctx->Shared->HandlesMutex);
> + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexture*HandleARB()");
> + return 0;
> + }
> +
> + /* Store the handle into the texture object. */
> + texHandleObj->texObj = texObj;
> + texHandleObj->sampObj = separate_sampler ? sampObj : NULL;
> + texHandleObj->handle = handle;
> + util_dynarray_append(&texObj->SamplerHandles,
> + struct gl_texture_handle_object *, texHandleObj);
> +
> + if (separate_sampler) {
> + /* Store the handle into the separate sampler if needed. */
> + util_dynarray_append(&sampObj->Handles,
> + struct gl_texture_handle_object *, 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. */
> + _mesa_hash_table_u64_insert(ctx->Shared->TextureHandles, handle,
> + texHandleObj);
> + mtx_unlock(&ctx->Shared->HandlesMutex);
> +
> + return handle;
> +}
> +
> +static struct gl_image_handle_object *
> +find_imghandleobj(struct gl_texture_object *texObj, GLint level,
> + GLboolean layered, GLint layer, GLenum format)
> +{
> + util_dynarray_foreach(&texObj->ImageHandles,
> + struct gl_image_handle_object *, imgHandleObj) {
> + struct gl_image_unit *u = &(*imgHandleObj)->imgObj;
> +
> + if (u->TexObj == texObj && 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;
> + }
> +
> + imgHandleObj = CALLOC_STRUCT(gl_image_handle_object);
> + if (!imgHandleObj) {
> + mtx_unlock(&ctx->Shared->HandlesMutex);
> + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetImageHandleARB()");
> + return 0;
> + }
> +
> + /* Store the handle into the texture object. */
> + memcpy(&imgHandleObj->imgObj, &imgObj, sizeof(struct gl_image_unit));
> + imgHandleObj->handle = handle;
> + util_dynarray_append(&texObj->ImageHandles,
> + struct gl_image_handle_object *, imgHandleObj);
> +
> + /* 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_u64_insert(ctx->Shared->ImageHandles, handle, imgHandleObj);
> + mtx_unlock(&ctx->Shared->HandlesMutex);
> +
> + return handle;
> +}
> +
> +/**
> + * Init/free per-context resident handles.
> + */
> +void
> +_mesa_init_resident_handles(struct gl_context *ctx)
> +{
> + ctx->ResidentTextureHandles = _mesa_hash_table_u64_create(NULL);
> + ctx->ResidentImageHandles = _mesa_hash_table_u64_create(NULL);
> +}
> +
> +void
> +_mesa_free_resident_handles(struct gl_context *ctx)
> +{
> + _mesa_hash_table_u64_destroy(ctx->ResidentTextureHandles, NULL);
> + _mesa_hash_table_u64_destroy(ctx->ResidentImageHandles, NULL);
> +}
> +
> +/**
> + * Init/free shared allocated handles.
> + */
> +void
> +_mesa_init_shared_handles(struct gl_shared_state *shared)
> +{
> + shared->TextureHandles = _mesa_hash_table_u64_create(NULL);
> + shared->ImageHandles = _mesa_hash_table_u64_create(NULL);
> + mtx_init(&shared->HandlesMutex, mtx_recursive);
> +}
> +
> +void
> +_mesa_free_shared_handles(struct gl_shared_state *shared)
> +{
> + _mesa_hash_table_u64_destroy(shared->TextureHandles, NULL);
> + _mesa_hash_table_u64_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)
> +{
> + util_dynarray_init(&texObj->SamplerHandles, NULL);
> + util_dynarray_init(&texObj->ImageHandles, NULL);
> +}
> +
> +void
> +_mesa_make_texture_handles_non_resident(struct gl_context *ctx,
> + struct gl_texture_object *texObj)
> +{
> + mtx_lock(&ctx->Shared->HandlesMutex);
> +
> + /* Texture handles */
> + util_dynarray_foreach(&texObj->SamplerHandles,
> + struct gl_texture_handle_object *, texHandleObj) {
> + if (is_texture_handle_resident(ctx, (*texHandleObj)->handle))
> + make_texture_handle_resident(ctx, *texHandleObj, false);
> + }
> +
> + /* Image handles */
> + util_dynarray_foreach(&texObj->ImageHandles,
> + struct gl_image_handle_object *, imgHandleObj) {
> + 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)
> +{
> + /* Texture handles */
> + util_dynarray_foreach(&texObj->SamplerHandles,
> + struct gl_texture_handle_object *, texHandleObj) {
> + struct gl_sampler_object *sampObj = (*texHandleObj)->sampObj;
> +
> + if (sampObj) {
> + /* Delete the handle in the separate sampler object. */
> + util_dynarray_delete_unordered(&sampObj->Handles,
> + struct gl_texture_handle_object *,
> + *texHandleObj);
> + }
> + delete_texture_handle(ctx, (*texHandleObj)->handle);
> + free(*texHandleObj);
> + }
> + util_dynarray_fini(&texObj->SamplerHandles);
> +
> + /* Image handles */
> + util_dynarray_foreach(&texObj->ImageHandles,
> + struct gl_image_handle_object *, imgHandleObj) {
> + delete_image_handle(ctx, (*imgHandleObj)->handle);
> + free(*imgHandleObj);
> + }
> + util_dynarray_fini(&texObj->ImageHandles);
> +}
> +
> +/**
> + * Init/free texture handles per-sampler object.
> + */
> +void
> +_mesa_init_sampler_handles(struct gl_sampler_object *sampObj)
> +{
> + util_dynarray_init(&sampObj->Handles, NULL);
> +}
> +
> +void
> +_mesa_delete_sampler_handles(struct gl_context *ctx,
> + struct gl_sampler_object *sampObj)
> +{
> + util_dynarray_foreach(&sampObj->Handles,
> + struct gl_texture_handle_object *, texHandleObj) {
> + struct gl_texture_object *texObj = (*texHandleObj)->texObj;
> +
> + /* Delete the handle in the texture object. */
> + util_dynarray_delete_unordered(&texObj->SamplerHandles,
> + struct gl_texture_handle_object *,
> + *texHandleObj);
> +
> + delete_texture_handle(ctx, (*texHandleObj)->handle);
> + free(*texHandleObj);
> + }
> + util_dynarray_fini(&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 88b84ce275b..d584f5cc0cc 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
> */
> /*@{*/
>
--
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.
More information about the mesa-dev
mailing list