Glpixelstorei(Gl_Unpack_Alignment, 1) Disadvantages

glPixelStorei(GL_UNPACK_ALIGNMENT, 1) Disadvantages?

How can data not be 1-byte aligned?

This strongly suggests a lack of understanding of what the row alignment in pixel transfer operations means.

Image data that you pass to OpenGL is expected to be grouped into rows. Each row contains width number of pixels, with each pixel being the size as defined by the format and type parameters. So a format of GL_RGB with a type of GL_UNSIGNED_BYTE will result in a pixel that is 24-bits in size. Pixels are otherwise expected to be packed, so a row of 16 of these pixels will take up 48 bytes.

Each row is expected to be aligned on a specific value, as defined by the GL_PACK/UNPACK_ALIGNMENT. This means that the value you add to the pointer to get to the next row is: align(pixel_size * width, GL_*_ALIGNMENT). If the pixel size is 3-bytes, the width is 2, and the alignment is 1, the row byte size is 6. If the alignment is 4, the row byte size is eight.

See the problem?

Image data, which may come from some image file format as loaded with some image loader, has a row alignment. Sometimes this is 1-byte aligned, and sometimes it isn't. DDS images have an alignment specified as part of the format. In many cases, images have 4-byte row alignments; pixel sizes less than 32-bits will therefore have padding at the end of rows with certain widths. If the alignment you give OpenGL doesn't match that, then you get a malformed texture.

You set the alignment to match the image format's alignment. If you know or otherwise can ensure that your row alignment is always 1 (and that's unlikely unless you've written your own image format or DDS writer), you need to set the row alignment to be exactly what your image format uses.

OpenGL GL_UNPACK_ALIGNMENT

The GL_UNPACK_ALIGNMENT value should not come into play here. The default value is 4. Since you have 4 bytes per pixel when using RGBA values, the size of a row is always a multiple of 4.

The value only needs to be changed if the amount of data per row is not a multiple of 4. For example, if you have RGB data, with 3 bytes per pixel, you have to change it to 1, unless the rows are actually aligned to 4 byte multiples with extra padding.

The real problem I see in your code is the loop:

for(unsigned int i = 0; i < size; i += depth){
MScriptUtil::setUcharArray(pixels, i+0, (int)floorf(color[0] * 255.0f + 0.5f));
MScriptUtil::setUcharArray(pixels, i+1, (int)floorf(color[1] * 255.0f + 0.5f));
MScriptUtil::setUcharArray(pixels, i+2, (int)floorf(color[2] * 255.0f + 0.5f));
pixels[i + 3] = 255;
}

Since size is 256, this will only fill the first 256 bytes (corresponding to 64 pixels) with data. To match the definitions and the rest of your code, this loop should be:

for(unsigned int i = 0; i < size * size * depth; i += depth) {

glTexImage2D slicing and alignment issues appearing in window

This looks like row misalignment, caused by the 3-wide colour data. Try using the following call just before glTexImage2D:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

This alignment value, which is 4 by default, is used by glTexImage2D and friends whenever texture data is read to be sent to the GPU.

There is no verification that it matches what the data actually looks like, so in cases like yours where a row doesn't end on a 4-byte boundary, the first few bytes of the next row will be skipped, leading to this diagonal distortion.

Texture data transfers in the other direction (from the GPU to client memory) are aligned via glPixelStorei(GL_PACK_ALIGNMENT, 1);.

Failing to map a simple unsigned byte rgb texture to a quad:

GL_UNPACK_ALIGNMENT specifies the alignment requirements for the start of each pixel row in memory. By default GL_UNPACK_ALIGNMENT is set to 4.
This means each row of the texture is supposed to have a length of 4*N bytes.

You specify a 2*2 texture with the data: 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0

With GL_UNPACK_ALIGNMENT set to 4 this is interpreted as

         column 1          column 2              alignment
row 1: 255, 0, 0, 255, 0, 0, 255, 0,
row 2: 0, 255, 0, 0, undef, undef

So the texture is read as

          column 1   olumn 2  
row 1: red, red,
row 2: green, RGB(0, ?, ?)

You have to set glPixelStorei(GL_UNPACK_ALIGNMENT, 1); before glTextureSubImage2D, for reading a tight packed texture.

If you do not want to change GL_UNPACK_ALIGNMENT (the alignment remains set to 4), you must adjust the data as follows:

struct DummyRGB8Texture2d
{
uint8_t data[8*2];
int width;
int height;
};

DummyRGB8Texture2d myTexture
{
{
255, 0, 0, 255, 0, 0, // row 1
0, 0, // 2 bytes alignment
255, 0, 0, 255, 0, 0, // row 2
0, 0 // 2 bytes alignment
},
2u,
2u
};


See further:
  • Stackoverflow question glPixelStorei(GL_UNPACK_ALIGNMENT, 1) Disadvantages?
  • Stackoverflow question OpenGL GL_UNPACK_ALIGNMENT
  • Khronos OpenGL Common Mistakes - Texture upload and pixel reads

PNG saved from OpenGL framebuffer using stbi_write_png is shifted to the right

The issue is cause be the alignment of a row, when the image is read by glReadPixels. By default the alignment of the start of each row of the image is assumed to be 4.

Since the width of the image is 450, which is not divisible by 4 (450/4 = 112.5) and the format is RGB (3 bytes), the alignment has to be changed.

Change the GL_PACK_ALIGNMENT (glPixelStore) before reading the image data:

glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);

opengl : glGetTexImage for 2d textures and 1d texture array confusion

As per the documentation it writes 4 bytes per pixels [...]

No it does not. glGetTexImage(...GL_RGB, GL_UNSIGNED_BYTE...) reads 3 bytes per pixel. The length of a line is aligned to 4 bytes (if GL_PACK_ALIGNMENT is 4).

The arguments format and _type of glGetTexImage do not specify the format of the source texture, but the format of the target buffer.



Related Topics



Leave a reply



Submit