| /* |
| * Copyright © 2017 Valve Corporation. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include "glheader.h" |
| #include "context.h" |
| #include "enums.h" |
| |
| #include "hash.h" |
| #include "mtypes.h" |
| #include "shaderimage.h" |
| #include "teximage.h" |
| #include "texobj.h" |
| #include "texturebindless.h" |
| |
| #include "util/hash_table.h" |
| #include "util/u_memory.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; |
| 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) |
| { |
| if (shared->TextureHandles) |
| _mesa_hash_table_u64_destroy(shared->TextureHandles, NULL); |
| |
| if (shared->ImageHandles) |
| _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_no_error(GLuint texture) |
| { |
| struct gl_texture_object *texObj; |
| |
| GET_CURRENT_CONTEXT(ctx); |
| |
| texObj = _mesa_lookup_texture(ctx, texture); |
| if (!_mesa_is_texture_complete(texObj, &texObj->Sampler, |
| ctx->Const.ForceIntegerTexNearest)) |
| _mesa_test_texobj_completeness(ctx, texObj); |
| |
| return get_texture_handle(ctx, texObj, &texObj->Sampler); |
| } |
| |
| GLuint64 GLAPIENTRY |
| _mesa_GetTextureHandleARB(GLuint texture) |
| { |
| 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, |
| ctx->Const.ForceIntegerTexNearest)) { |
| _mesa_test_texobj_completeness(ctx, texObj); |
| if (!_mesa_is_texture_complete(texObj, &texObj->Sampler, |
| ctx->Const.ForceIntegerTexNearest)) { |
| _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_no_error(GLuint texture, GLuint sampler) |
| { |
| struct gl_texture_object *texObj; |
| struct gl_sampler_object *sampObj; |
| |
| GET_CURRENT_CONTEXT(ctx); |
| |
| texObj = _mesa_lookup_texture(ctx, texture); |
| sampObj = _mesa_lookup_samplerobj(ctx, sampler); |
| |
| if (!_mesa_is_texture_complete(texObj, sampObj, |
| ctx->Const.ForceIntegerTexNearest)) |
| _mesa_test_texobj_completeness(ctx, texObj); |
| |
| return get_texture_handle(ctx, texObj, sampObj); |
| } |
| |
| GLuint64 GLAPIENTRY |
| _mesa_GetTextureSamplerHandleARB(GLuint texture, GLuint sampler) |
| { |
| 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, |
| ctx->Const.ForceIntegerTexNearest)) { |
| _mesa_test_texobj_completeness(ctx, texObj); |
| if (!_mesa_is_texture_complete(texObj, sampObj, |
| ctx->Const.ForceIntegerTexNearest)) { |
| _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_no_error(GLuint64 handle) |
| { |
| struct gl_texture_handle_object *texHandleObj; |
| |
| GET_CURRENT_CONTEXT(ctx); |
| |
| texHandleObj = lookup_texture_handle(ctx, handle); |
| make_texture_handle_resident(ctx, texHandleObj, true); |
| } |
| |
| 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_no_error(GLuint64 handle) |
| { |
| struct gl_texture_handle_object *texHandleObj; |
| |
| GET_CURRENT_CONTEXT(ctx); |
| |
| texHandleObj = lookup_texture_handle(ctx, handle); |
| make_texture_handle_resident(ctx, texHandleObj, false); |
| } |
| |
| 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_no_error(GLuint texture, GLint level, GLboolean layered, |
| GLint layer, GLenum format) |
| { |
| struct gl_texture_object *texObj; |
| |
| GET_CURRENT_CONTEXT(ctx); |
| |
| texObj = _mesa_lookup_texture(ctx, texture); |
| if (!_mesa_is_texture_complete(texObj, &texObj->Sampler, |
| ctx->Const.ForceIntegerTexNearest)) |
| _mesa_test_texobj_completeness(ctx, texObj); |
| |
| return get_image_handle(ctx, texObj, level, layered, layer, format); |
| } |
| |
| GLuint64 GLAPIENTRY |
| _mesa_GetImageHandleARB(GLuint texture, GLint level, GLboolean layered, |
| GLint layer, GLenum format) |
| { |
| 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, |
| ctx->Const.ForceIntegerTexNearest)) { |
| _mesa_test_texobj_completeness(ctx, texObj); |
| if (!_mesa_is_texture_complete(texObj, &texObj->Sampler, |
| ctx->Const.ForceIntegerTexNearest)) { |
| _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_no_error(GLuint64 handle, GLenum access) |
| { |
| struct gl_image_handle_object *imgHandleObj; |
| |
| GET_CURRENT_CONTEXT(ctx); |
| |
| imgHandleObj = lookup_image_handle(ctx, handle); |
| make_image_handle_resident(ctx, imgHandleObj, access, true); |
| } |
| |
| 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_no_error(GLuint64 handle) |
| { |
| struct gl_image_handle_object *imgHandleObj; |
| |
| GET_CURRENT_CONTEXT(ctx); |
| |
| imgHandleObj = lookup_image_handle(ctx, handle); |
| make_image_handle_resident(ctx, imgHandleObj, GL_READ_ONLY, false); |
| } |
| |
| 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_no_error(GLuint64 handle) |
| { |
| GET_CURRENT_CONTEXT(ctx); |
| return is_texture_handle_resident(ctx, handle); |
| } |
| |
| GLboolean GLAPIENTRY |
| _mesa_IsTextureHandleResidentARB(GLuint64 handle) |
| { |
| 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_no_error(GLuint64 handle) |
| { |
| GET_CURRENT_CONTEXT(ctx); |
| return is_image_handle_resident(ctx, handle); |
| } |
| |
| GLboolean GLAPIENTRY |
| _mesa_IsImageHandleResidentARB(GLuint64 handle) |
| { |
| 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); |
| } |