void GLAPIENTRY _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { GET_CURRENT_CONTEXT(ctx); struct gl_image_unit *u; if (!validate_bind_image_texture(ctx, unit, texture, level, layered, layer, access, format)) return; u = &ctx->ImageUnits[unit]; FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; if (texture) { struct gl_texture_object *t = _mesa_lookup_texture(ctx, texture); if (!t) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(texture)"); return; } /* From section 8.22 "Texture Image Loads and Stores" of the OpenGL ES * 3.1 spec: * * "An INVALID_OPERATION error is generated if texture is not the name * of an immutable texture object." */ if (_mesa_is_gles(ctx) && !t->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTexture(!immutable)"); return; } _mesa_reference_texobj(&u->TexObj, t); } else { _mesa_reference_texobj(&u->TexObj, NULL); } u->Level = level; u->Access = access; u->Format = format; u->_ActualFormat = _mesa_get_shader_image_format(format); if (u->TexObj && _mesa_tex_target_is_layered(u->TexObj->Target)) { u->Layered = layered; u->Layer = layer; u->_Layer = (u->Layered ? 0 : u->Layer); } else { u->Layered = GL_FALSE; u->Layer = 0; } if (ctx->Driver.BindImageTexture) ctx->Driver.BindImageTexture(ctx, u, u->TexObj, level, layered, layer, access, format); }
GLboolean _mesa_is_image_unit_valid(struct gl_context *ctx, struct gl_image_unit *u) { struct gl_texture_object *t = u->TexObj; mesa_format tex_format; if (!t) return GL_FALSE; if (!t->_BaseComplete && !t->_MipmapComplete) _mesa_test_texobj_completeness(ctx, t); if (u->Level < t->BaseLevel || u->Level > t->_MaxLevel || (u->Level == t->BaseLevel && !t->_BaseComplete) || (u->Level != t->BaseLevel && !t->_MipmapComplete)) return GL_FALSE; if (_mesa_tex_target_is_layered(t->Target) && u->_Layer >= _mesa_get_texture_layers(t, u->Level)) return GL_FALSE; if (t->Target == GL_TEXTURE_BUFFER) { tex_format = _mesa_get_shader_image_format(t->BufferObjectFormat); } else { struct gl_texture_image *img = (t->Target == GL_TEXTURE_CUBE_MAP ? t->Image[u->_Layer][u->Level] : t->Image[0][u->Level]); if (!img || img->Border || img->NumSamples > ctx->Const.MaxImageSamples) return GL_FALSE; tex_format = _mesa_get_shader_image_format(img->InternalFormat); } if (!tex_format) return GL_FALSE; switch (t->ImageFormatCompatibilityType) { case GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE: if (_mesa_get_format_bytes(tex_format) != _mesa_get_format_bytes(u->_ActualFormat)) return GL_FALSE; break; case GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS: if (get_image_format_class(tex_format) != get_image_format_class(u->_ActualFormat)) return GL_FALSE; break; default: assert(!"Unexpected image format compatibility type"); } return GL_TRUE; }
void GLAPIENTRY _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_object *t = NULL; struct gl_image_unit *u; if (!validate_bind_image_texture(ctx, unit, texture, level, layered, layer, access, format)) return; u = &ctx->ImageUnits[unit]; FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; if (texture) { t = _mesa_lookup_texture(ctx, texture); if (!t) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(texture)"); return; } _mesa_reference_texobj(&u->TexObj, t); u->Level = level; u->Access = access; u->Format = format; u->_ActualFormat = get_image_format(format); if (_mesa_tex_target_is_layered(t->Target)) { u->Layered = layered; u->Layer = (layered ? 0 : layer); } else { u->Layered = GL_FALSE; u->Layer = 0; } } else { _mesa_reference_texobj(&u->TexObj, NULL); } u->_Valid = validate_image_unit(ctx, u); if (ctx->Driver.BindImageTexture) ctx->Driver.BindImageTexture(ctx, u, t, level, layered, layer, access, format); }
static GLboolean validate_image_unit(struct gl_context *ctx, struct gl_image_unit *u) { struct gl_texture_object *t = u->TexObj; struct gl_texture_image *img; if (!t || u->Level < t->BaseLevel || u->Level > t->_MaxLevel) return GL_FALSE; _mesa_test_texobj_completeness(ctx, t); if ((u->Level == t->BaseLevel && !t->_BaseComplete) || (u->Level != t->BaseLevel && !t->_MipmapComplete)) return GL_FALSE; if (_mesa_tex_target_is_layered(t->Target) && u->Layer >= _mesa_get_texture_layers(t, u->Level)) return GL_FALSE; if (t->Target == GL_TEXTURE_CUBE_MAP) img = t->Image[u->Layer][u->Level]; else img = t->Image[0][u->Level]; if (!img || img->Border || get_image_format_class(img->TexFormat) == IMAGE_FORMAT_CLASS_NONE || img->NumSamples > ctx->Const.MaxImageSamples) return GL_FALSE; switch (t->ImageFormatCompatibilityType) { case GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE: if (_mesa_get_format_bytes(img->TexFormat) != _mesa_get_format_bytes(u->_ActualFormat)) return GL_FALSE; break; case GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS: if (get_image_format_class(img->TexFormat) != get_image_format_class(u->_ActualFormat)) return GL_FALSE; break; default: assert(!"Unexpected image format compatibility type"); } return GL_TRUE; }
void GLAPIENTRY _mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures) { GET_CURRENT_CONTEXT(ctx); int i; if (!ctx->Extensions.ARB_shader_image_load_store) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures()"); return; } if (first + count > ctx->Const.MaxImageUnits) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if <first> + <count> * is greater than the number of image units supported by * the implementation." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(first=%u + count=%d > the value of " "GL_MAX_IMAGE_UNITS=%u)", first, count, ctx->Const.MaxImageUnits); return; } /* Assume that at least one binding will be changed */ FLUSH_VERTICES(ctx, 0); ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; /* Note that the error semantics for multi-bind commands differ from * those of other GL commands. * * The Issues section in the ARB_multi_bind spec says: * * "(11) Typically, OpenGL specifies that if an error is generated by * a command, that command has no effect. This is somewhat * unfortunate for multi-bind commands, because it would require * a first pass to scan the entire list of bound objects for * errors and then a second pass to actually perform the * bindings. Should we have different error semantics? * * RESOLVED: Yes. In this specification, when the parameters for * one of the <count> binding points are invalid, that binding * point is not updated and an error will be generated. However, * other binding points in the same command will be updated if * their parameters are valid and no other error occurs." */ _mesa_begin_texture_lookups(ctx); for (i = 0; i < count; i++) { struct gl_image_unit *u = &ctx->ImageUnits[first + i]; const GLuint texture = textures ? textures[i] : 0; if (texture != 0) { struct gl_texture_object *texObj; GLenum tex_format; if (!u->TexObj || u->TexObj->Name != texture) { texObj = _mesa_lookup_texture_locked(ctx, texture); if (!texObj) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if any value * in <textures> is not zero or the name of an existing * texture object (per binding)." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(textures[%d]=%u " "is not zero or the name of an existing texture " "object)", i, texture); continue; } } else { texObj = u->TexObj; } if (texObj->Target == GL_TEXTURE_BUFFER) { tex_format = texObj->BufferObjectFormat; } else { struct gl_texture_image *image = texObj->Image[0][0]; if (!image || image->Width == 0 || image->Height == 0 || image->Depth == 0) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if the width, * height, or depth of the level zero texture image of * any texture in <textures> is zero (per binding)." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(the width, height or depth " "of the level zero texture image of " "textures[%d]=%u is zero)", i, texture); continue; } tex_format = image->InternalFormat; } if (_mesa_get_shader_image_format(tex_format) == MESA_FORMAT_NONE) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if the internal * format of the level zero texture image of any texture * in <textures> is not found in table 8.33 (per binding)." */ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures(the internal format %s of " "the level zero texture image of textures[%d]=%u " "is not supported)", _mesa_lookup_enum_by_nr(tex_format), i, texture); continue; } /* Update the texture binding */ _mesa_reference_texobj(&u->TexObj, texObj); u->Level = 0; u->Layered = _mesa_tex_target_is_layered(texObj->Target); u->Layer = 0; u->Access = GL_READ_WRITE; u->Format = tex_format; u->_ActualFormat = _mesa_get_shader_image_format(tex_format); u->_Valid = validate_image_unit(ctx, u); } else { /* Unbind the texture from the unit */ _mesa_reference_texobj(&u->TexObj, NULL); u->Level = 0; u->Layered = GL_FALSE; u->Layer = 0; u->Access = GL_READ_ONLY; u->Format = GL_R8; u->_ActualFormat = MESA_FORMAT_R_UNORM8; u->_Valid = GL_FALSE; } /* Pass the BindImageTexture call down to the device driver */ if (ctx->Driver.BindImageTexture) ctx->Driver.BindImageTexture(ctx, u, u->TexObj, u->Level, u->Layered, u->Layer, u->Access, u->Format); } _mesa_end_texture_lookups(ctx); }