# How can I use an unsigned int as a GLSL attribute for OpenGL ES 2

I'm having trouble finding conclusive information on this, but it seems like I can't pass integer attributes to GLSL for OpenGL ES or that if I do they'll be converted to float. I need a value between the range [0-65535] for each vertex. If I pass it as a float and then convert it back, I'm concerned that the value will have changed (if the precision is low enough and can't suitably represent values at the higher magnitudes).

Its also confusing trying to figure out what precision for floats the OpenGL ES 2 standard requires. It seems like the minimum requirement is 16-bit (ie some implementations will use 16-bit floats for highp variables). In this case, it would seem like the floating point number wouldn't be able to store enough information for 0-65535 since that's what a 16-bit unsigned int holds.

So, formally, how can I specify a vertex attribute that will let me precisely represent the values 0-65535 in OpenGL ES 2.

• What is the purpose of that integer? You could always send it as two 8-bit integers and combine them later if necessary. – sam hocevar Jan 12 '13 at 18:09
• I batch geometry and use the integer to identify geometry as belonging to separate entities. With regards to sending it as two 8-bit integers... I think you can only use float attributes in your shaders. I don't know how I'd combine two ints [represented as floats] into one int, or even if thats necessary. – Pris Jan 12 '13 at 20:01
• Yes, integers passed as attributes are converted to floats, but 0 - 255 can be exactly represented by a shader variable. – sam hocevar Jan 13 '13 at 0:00

Programming in GLESSL is a bit different than programming for a normal CPU.

Since you're using OpenGLES 2, I will assume you are using GLESSL 1.0. So I will be pulling quotes from its documentation.

In general, GLESSL offers you a variety of types as programming aids, with some guarantees regarding their behavior, but leaves the actual low level implementation details to the manufacturer of a specific GPU.

GLESSL is not a low level programming language (like C), and as such, talking about bit representations in GLESSL is mostly meaningless.

According to section 4.5.1 of the documentation:

The vertex language must provide an integer precision of at least 16 bits, plus a sign bit.

That means that for the vertex shader, you can safely use values from -65536 to 65536 with a highp int, something which is repeated in table 2 of section 4.5.2.

This may sound strange if you're accustomed to thinking of 16 bit ints being able to represent values between -32768 and 35767. GLESSL does not specify how ints are to be represented internally, just that they must provide enough precision for numbers between -65536 and 65536, which should be enough for your purposes.

In fact, as section 4.1.3 implies, ints are meant to be programming aids, and there is no guarantee that the underlying representation must be a hardware integer. In most cases, all operations will be performed on hardware floats (probably 32-bit, even for lowp), but GPUs are free to implement them any way they like, even as textual representations in Swedish using EBCDIC.

In practical terms, in the vertex shader, you can use int (highp is implied, as per section 10.3), and you are guaranteed to be able to store values from -65536 to 65536. Also, you can use float and have at least 16 bits of precision (plus one bit sign) for any given exponenent within range, which means that you can also use float for your purposes. This is also clarified in section 4.5.2:

a highp int can be represented by a highp float.

I would recommend you take floats, and pass floats from your program, since it is very likely that any given GPU uses floats to represent ints. If you pass ints, it is very likely that a costly conversion will take place.

Also, there is glGetShaderPrecisionFormat if you want to know the exact precision of a given type in a given GPU. I would rather rely on the guarantees given by the standard.

As far as I know, precision qualifiers are more about bandwidth than actual calculations. Mobile GPUs are very limited in terms of bandwidth, and specifying that you can live with lowp on a particular varying variable, may allow the GPU to perform better packing strategies and give you better performance than if you specify you require highp.

• You can't specify integer attributes in OpenGL ES 2, only floats. But as you said, 4.5.2 implies you can use a highp float attribute and it should be able to represent each integer between -65536 and 65536. "For high and medium precisions, integer ranges must be such that they can be accurately represented by the corresponding floating point value of the same precision qualifier. That is, a highp int can be represented by a highp float, a mediump int can be represented by a mediump float" – Pris Oct 16 '14 at 17:02

I'm answering based on my OpenGL non-ES knowledge, which I hope works on ES as well.

It sounds like you want to use GLushort in your C code, referred to as GL_UNSIGNED_SHORT when passing the data to OpenGL in C, and then use type int or uint in GLSL.

One gotcha is to use the function VertexAttribIPointer instead of VertexAttribPointer when sending the data to OpenGL; the difference is that you want to include the letter I (for integer) before the word Pointer.

Based on this list of GLSL data types, I don't think GLSL explicitly has a 16-bit integer type, but it has 32-bit types that should work fine.