How does GL_UNPACK_ALIGNMENT work?

I have searched online for about 3 days now but i’m still not getting the concept of how GL_(UN)PACK_ALIGNMENT works.

Let’s say I have 2 pixel row that is 7 pixels long each.

[1][2][3][4][5][6][7]
[1][2][3][4][5][6][7]

Each pixel is consist of 3 bytes. (GL_RGB)

(I think) The right alignment setting for this particular situation is,

glPixelSotrei(GL_UNPACK_ALIGNMENT, 4);

(Please correct me if i’m wrong.)

Now here’s what I think OpenGL would do,

[address-0][address-1][address-2][address-3][address-4][address-5][address-6]…
[pixel-1-R][pixel-1-G][pixel-1-B][ padding ][pixel-2-R][pixel-2-G][pixel-2-B]…

Because each pixel is 3 bytes long each, I think OpenGL would put pad every fourth address.

From OpenGL official forum,

link: https://www.opengl.org/discussion_boards/showthread.php/197557-What-does-glPixelStore()-do?p=1279239#post1279239

He says,

Suppose that you have texture data with GL_RGB format (3 bytes per component) and a width of 123, with no padding between rows (i.e. the first byte of the first pixel of one row immediately follows the last byte of the last pixel of the previous row). The stride between rows will be 3*123 = 369 bytes. Note that 369 is not a multiple of 2 or 4.

Why does row length matter? I thought alignment works with each single pixels, not each rows. Or am I wrong?

Thanks.

Wrong, the correct alignment for tightly packed GL_RGB unsigned byte data is 1.
Unpack alignment would only work with your settings if the row length is coincidentally a multiple of four bytes, which 7 * 3 bytes isn’t.
The resulting image should have diagonally sheared incorrect color components because after the first row has been read, the next row starts to read on a four bytes aligned address with unpack_alignment set to 4.

The OpenGL 4.5 core specs say “The values of UNPACK_ROW_LENGTH and UNPACK_ALIGNMENT control the row-to-row spacing in these images as described in section 8.4.4”.
Formulas (8.1) and (8.2) are what you need to look at.

So that means I can only use GL_UNPACK_ALIGNMENT when my row length * bytes is divisible by 2, 4 and 8, is this correct?

So back to the example, if my row length was 4 instead of 7, my alignment would be 4, because 4 * 3 is 12 and 12 is divisible by 4.

If my row length was 8 instead of 7, my alignment would be 8? because 8 * 3 is 24 and 24 is divisible by 8. But would alignment 4 also work as well because 24 is also divisible by 4?

Thanks for the help.

Not exactly. OpenGL is a state machine, there is always an unpack alignment active and the default is 4.
If the default doesn’t work for your data layout, you must set GL_UNPACK_ALIGNMENT to an allowed value which works before the next operation which uses the PixelStore values. Simple as that.

Allowed values are 1, 2, 4, 8 as listed in the OpenGL 4.5 core spec chapter 8.4 table 8.1 on page 178.
For GL_RGB only 1 will work for all cases, including odd row widths, so simply use that for this user data layout.

Other cases like GL_RGBA unsigned byte or anything with float data can use the default GL_UNPACK_ALIGNMENT 4 because each element is a multiple of four bytes.
There are only a few cases which require an alignment of 2 like GL_RED unsigned short.

And yes, things work by chance if the row length in bytes is coincidentally aligned, but that wouldn’t be robust code. I’d recommend to select the unpack alignment value based on the size of a single pixel/texel. The row length has a separate value, and there are skip values as well because OpenGL allows to transfer sub-rectangles in a bigger pixel area.

All core specs and extension documentations can be found here:
https://www.opengl.org/registry/
You need to read these if you have any question about how OpenGL is supposed to work exactly.