2

I have seen (several) (semi)-(related) (posts) (about) this, but none answers the following question directly:

When exactly does glTexImage.D clamp input values to [0,1]?

The documentation seems to imply that it always does (with the possible exception of GL_DEPTH_STENCIL, which I seem to remember being disallowed, although the documentation doesn't support this). This is how I'm currently handling it in my code.

Other of the linked sources seem to suggest that data is clamped exactly when it is converted to a normalized color format, or that it is only clamped when the image format is integral. To confirm this, I tested a GL_RGBAF32 internal format: negative float data are clamped to 0, while positive data aren't clamped at all.

Then there's (all combinations of) unsigned/signed normalized/unnormalized integer internal formats.

So, when does pixel unpack, specifically glTexImage.D, clamp data? I'm specifically interested in GL_((R|RG|RGB|RGBA)((8|16|32)(|I|UI|_SNORM)|(16F|32F))|DEPTH_COMPONENT(16|24|32)) (i.e., all the color floating-point and integer textures, plus all depth textures), but probably all internal formats should be addressed.

Community
  • 1
  • 1
geometrian
  • 14,775
  • 10
  • 56
  • 132

1 Answers1

1

It does not have to clamp anything, technically.

One place this behavior is defined is by the pixel transfer operation. In other words, if the internal format and the format of the data you are transfering into the texture differ, then lots of interesting things can happen including scaling/clamping to a certain range. If you properly match internal format and pixel transfer format you can avoid implicit normalization and clamping of the image data since no conversion will be necessary.

Of course, pixel transfer is only one source of clamping. In GL4.3 you can share the underlying data store between multiple texture objects and change the internal format for compatible image classes (e.g. any 32-bit texture format) using texture views. That can be used to reinterpret UNORM image data as SNORM when sampled, for example.


I should probably explain that something like GL_RGB8 is fixed-point... more specifically, it is Unsigned Normalized (UNORM). If you were to transfer image data into a GL_RGBA32F image using GL_RGBA as the pixel transfer format and GL_UNSIGNED_BYTE as the data type GL will interpret that as conversion from GL_RGBA8 (source format) to GL_RGBA32F (internal format).

In GLES you must always match these formats because pixel transfer conversion is undefined. In desktop GL, however, this example is going to produce values only in the range [0.0, 1.0]. If you wanted the range to be [-1.0, 1.0] you would need to use an SNORM format.

It works the other way around too, if you try to read from a texture with a different internal format and destination format. If you want to get the proper values into / out of your texture, you need to avoid pixel transfer conversion.


OpenGL 4.4 Core Profile Specification - 8.5 Texture Image Specification - pp. 183

8.4.4.2 Conversion to floating-point

This step applies only to groups of floating-point components. It is not performed on indices or integer components. For groups containing both components and indices, such as GL_DEPTH_STENCIL, the indices are not converted.

Each element in a group is converted to a floating-point value. For unsigned or signed integer elements, equations 2.1 or 2.2, respectively, are used.

enter image description here enter image description here

The specification goes on later to further clarify this behavior for all classes of image data:

OpenGL 4.4 Core Profile Specification - 8.5 Texture Image Specification - pp. 184

The selected groups are transferred to the GL as described in section 8.4.4 and then clamped to the representable range of the internal format. If the internalformat of the texture is signed or unsigned integer, components are clamped to [−2n−1, 2n−1 − 1] or [0, 2n − 1], respectively, where n is the number of bits per component. For color component groups, if the internalformat of the texture is signed or unsigned normalized fixed-point, components are clamped to [−1, 1] or [0, 1], respectively. For depth component groups, the depth value is clamped to [0, 1]. Otherwise, values are not modified. Stencil index values are masked by 2n − 1, where n is the number of stencil bits in the internal format resolution (see below). If the base internal format is GL_DEPTH_STENCIL and format is not GL_DEPTH_STENCIL, then the values of the stencil index texture components are undefined.

Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106