On 05/22/2017 12:43 PM, Nicolai Hähnle wrote:
On 19.05.2017 18:52, Samuel Pitoiset wrote:Signed-off-by: Samuel Pitoiset <samuel.pitoi...@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 */Should be consistent with gl_sampler_object in terms of type (and gl_texture_object as well). Which type? Since the state is not API-visible, bool is justifiable.
Correct.
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.cindex 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);This won't work on 32-bit systems (same for image handles).
Because the handle is 64-bit? Mmh...
+ 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);+ }So... this also needs to loop through all other contexts and make the handle non-resident in them, right? Otherwise you might end up with dangling pointers (or at least dangling handles).
No. Resident handles are per-context. Though, I'm not very happy myself with the way I managed the handles. I'm open to any better suggestions.
+ + 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)) {|| instead of &&
Right.
+ _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)) {|| instead of &&+ _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)) {|| vs. &&+ _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)) {|| instead of && Cheers, Nicolai+ _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.hindex 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 */ /*@{*/
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev