diff options
author | Samuel Pitoiset <[email protected]> | 2017-04-03 22:06:27 +0200 |
---|---|---|
committer | Samuel Pitoiset <[email protected]> | 2017-06-14 10:04:35 +0200 |
commit | 1fe7b1f9724ac38cbddcac6505d3750ef99a2eca (patch) | |
tree | 96c8051197c169332feef881c98516126aa919c9 /src/mesa/main/texturebindless.c | |
parent | 6649b840c34016b4753e69d4513a8d09da9febb2 (diff) |
mesa: implement ARB_bindless_texture
Signed-off-by: Samuel Pitoiset <[email protected]>
Reviewed-by: Nicolai Hähnle <[email protected]>
Diffstat (limited to 'src/mesa/main/texturebindless.c')
-rw-r--r-- | src/mesa/main/texturebindless.c | 852 |
1 files changed, 845 insertions, 7 deletions
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); } |