+/**
+ * Helper for glTexBuffer(). Check if internalFormat is legal. If so,
+ * return the basic data type and number of components for the format.
+ * \param return GL_TRUE if internalFormat is legal, GL_FALSE otherwise
+ */
+static GLboolean
+get_sized_format_info(const struct gl_context *ctx, GLenum internalFormat,
+ GLenum *datatype, GLuint *components)
+{
+ switch (internalFormat) {
+ case GL_ALPHA8:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 1;
+ break;
+ case GL_ALPHA16:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 1;
+ break;
+ case GL_ALPHA16F_ARB:
+ *datatype = GL_HALF_FLOAT;
+ *components = 1;
+ break;
+ case GL_ALPHA32F_ARB:
+ *datatype = GL_FLOAT;
+ *components = 1;
+ break;
+ case GL_ALPHA8I_EXT:
+ *datatype = GL_BYTE;
+ *components = 1;
+ break;
+ case GL_ALPHA16I_EXT:
+ *datatype = GL_SHORT;
+ *components = 1;
+ break;
+ case GL_ALPHA32I_EXT:
+ *datatype = GL_INT;
+ *components = 1;
+ break;
+ case GL_ALPHA8UI_EXT:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 1;
+ break;
+ case GL_ALPHA16UI_EXT:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 1;
+ break;
+ case GL_ALPHA32UI_EXT:
+ *datatype = GL_UNSIGNED_INT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE8:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 1;
+ break;
+ case GL_LUMINANCE16:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE16F_ARB:
+ *datatype = GL_HALF_FLOAT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE32F_ARB:
+ *datatype = GL_FLOAT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE8I_EXT:
+ *datatype = GL_BYTE;
+ *components = 1;
+ break;
+ case GL_LUMINANCE16I_EXT:
+ *datatype = GL_SHORT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE32I_EXT:
+ *datatype = GL_INT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE8UI_EXT:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 1;
+ break;
+ case GL_LUMINANCE16UI_EXT:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE32UI_EXT:
+ *datatype = GL_UNSIGNED_INT;
+ *components = 1;
+ break;
+ case GL_LUMINANCE8_ALPHA8:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 2;
+ break;
+ case GL_LUMINANCE16_ALPHA16:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA16F_ARB:
+ *datatype = GL_HALF_FLOAT;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA32F_ARB:
+ *datatype = GL_FLOAT;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA8I_EXT:
+ *datatype = GL_BYTE;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA16I_EXT:
+ *datatype = GL_SHORT;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA32I_EXT:
+ *datatype = GL_INT;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA8UI_EXT:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA16UI_EXT:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 2;
+ break;
+ case GL_LUMINANCE_ALPHA32UI_EXT:
+ *datatype = GL_UNSIGNED_INT;
+ *components = 2;
+ break;
+ case GL_INTENSITY8:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 1;
+ break;
+ case GL_INTENSITY16:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 1;
+ break;
+ case GL_INTENSITY16F_ARB:
+ *datatype = GL_HALF_FLOAT;
+ *components = 1;
+ break;
+ case GL_INTENSITY32F_ARB:
+ *datatype = GL_FLOAT;
+ *components = 1;
+ break;
+ case GL_INTENSITY8I_EXT:
+ *datatype = GL_BYTE;
+ *components = 1;
+ break;
+ case GL_INTENSITY16I_EXT:
+ *datatype = GL_SHORT;
+ *components = 1;
+ break;
+ case GL_INTENSITY32I_EXT:
+ *datatype = GL_INT;
+ *components = 1;
+ break;
+ case GL_INTENSITY8UI_EXT:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 1;
+ break;
+ case GL_INTENSITY16UI_EXT:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 1;
+ break;
+ case GL_INTENSITY32UI_EXT:
+ *datatype = GL_UNSIGNED_INT;
+ *components = 1;
+ break;
+ case GL_RGBA8:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 4;
+ break;
+ case GL_RGBA16:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 4;
+ break;
+ case GL_RGBA16F_ARB:
+ *datatype = GL_HALF_FLOAT;
+ *components = 4;
+ break;
+ case GL_RGBA32F_ARB:
+ *datatype = GL_FLOAT;
+ *components = 4;
+ break;
+ case GL_RGBA8I_EXT:
+ *datatype = GL_BYTE;
+ *components = 4;
+ break;
+ case GL_RGBA16I_EXT:
+ *datatype = GL_SHORT;
+ *components = 4;
+ break;
+ case GL_RGBA32I_EXT:
+ *datatype = GL_INT;
+ *components = 4;
+ break;
+ case GL_RGBA8UI_EXT:
+ *datatype = GL_UNSIGNED_BYTE;
+ *components = 4;
+ break;
+ case GL_RGBA16UI_EXT:
+ *datatype = GL_UNSIGNED_SHORT;
+ *components = 4;
+ break;
+ case GL_RGBA32UI_EXT:
+ *datatype = GL_UNSIGNED_INT;
+ *components = 4;
+ break;
+ default:
+ return GL_FALSE;
+ }
+
+ if (*datatype == GL_FLOAT && !ctx->Extensions.ARB_texture_float)
+ return GL_FALSE;
+
+ if (*datatype == GL_HALF_FLOAT && !ctx->Extensions.ARB_half_float_pixel)
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+
+/** GL_ARB_texture_buffer_object */
+void GLAPIENTRY
+_mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
+{
+ struct gl_texture_object *texObj;
+ struct gl_buffer_object *bufObj;
+ GLenum dataType;
+ GLuint comps;
+
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+
+ if (!ctx->Extensions.ARB_texture_buffer_object) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer");
+ return;
+ }
+
+ if (target != GL_TEXTURE_BUFFER_ARB) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(target)");
+ return;
+ }
+
+ if (!get_sized_format_info(ctx, internalFormat, &dataType, &comps)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(internalFormat 0x%x)",
+ internalFormat);
+ return;
+ }
+
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (buffer && !bufObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer(buffer %u)", buffer);
+ return;
+ }
+
+ texObj = _mesa_get_current_tex_object(ctx, target);
+
+ _mesa_lock_texture(ctx, texObj);
+ {
+ _mesa_reference_buffer_object(ctx, &texObj->BufferObject, bufObj);
+ texObj->BufferObjectFormat = internalFormat;
+ }
+ _mesa_unlock_texture(ctx, texObj);
+}