0

I am using LUT files stored in .cube files for image post processing.

The LUT.cube file layout may look like this:

TITLE
LUT_3D_SIZE 2
    
1.000000 1.000000 1.000000 -> takes black pix. from input image and transfers to white output pix
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000
1.000000 1.000000 0.000000
1.000000 0.000000 1.000000
0.000000 1.000000 1.000000
0.000000 0.000000 0.000000 -> takes white pix. from input image and transfers to black output pix.

I load the raw data from the file to data vector (this part is 100% correct) and then load its data to GL_TEXTURE_3D and use it calling glActiveTexture(GL_TEXTURE0_ARB + unit); as a sampler3D in frag. shader utilizing GLSL texture(...) function for free interpolation.

  glGenTextures(1, &texID);
  glBindTexture(GL_TEXTURE_3D, texID);

  constexpr int MIPMAP_LEVEL = 0;  // I do not need any mipmapping for now.

  //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -> should I use this???

  glTexImage3D(
    GL_TEXTURE_3D,
    MIPMAP_LEVEL,
    GL_RGB,
    size.x,  // Size of the LUT 2, 33 etc., x == y == z.
    size.y,
    size.z,
    0,
    GL_RGB,
    GL_FLOAT,  // I assume this is correct regarding how are stored the data in the LUT .cube file.
    data
  );

  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, MIPMAP_LEVEL);

  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

  glBindTexture(GL_TEXTURE_3D, 0);

For simplycity lets say that input image is restricted to be RGB8 or RGB16 format.

This works OK, when LUT_3D_SIZE is 2 (I suppose any POT will work), producing expectable constant color transformation output.

However these LUT files can have LUT_3D_SIZE parameter of NPOT size - odd numbers like 33 typicaly and there is where I start to have problems and non-deterministic output (the output texture is varying every post process run - I assume this is because the non-aligned texture is filled with some random data).

How I should address this problem?

I guess I could use glPixelStorei(GL_PACK/UNPACK_ALIGNMENT, x); to compensate odd pixel row width (33), but I would like to understand what (math) is going on instead of trying to pick up some random alignment that would magicaly work for me. Also I am not sure if this is the real problem I am facing, so...

For clarification I am on desktop GL 3.3+ available, Nvidia card.

genpfault
  • 51,148
  • 11
  • 85
  • 139
CJ_Notned
  • 248
  • 2
  • 11
  • I found out the solution is to use `glPixelStorei(GL_UNPACK_ALIGNMENT, 4);` for mine case, but I am not completely sure why - I think it is because GL_FLOAT(32) * 3(RGB) = 96, so closest fitting POT is 128, which is 4 * 32, so the alignment must be 4 (I think...), But then I do not get why problem occures when row width is 33 (and not occures when it is 2), as 33 does not figure anywhere in my alignment "computation". – CJ_Notned Jan 10 '23 at 12:41
  • 1
    Which type does `data` have? GL_UNPACK_ALIGNMENT isn't directly related to POT/NPOT. It tells OpenGL at which byte alignment each row in the texture will start. The only important thing is that `width * channels * sizeof(pixel data type)` is dividable by the alignment. If you pass floats anyway, then an alignment of 4 should always be working since sizeof(float)==4 and your data will be byte aligned anyway. – BDL Jan 10 '23 at 23:02
  • Since this is nicely explained here and one answer also takes about the performance aspect, I tend to close this question as a duplicate of [glPixelStorei(GL_UNPACK_ALIGNMENT, 1) Disadvantages?](https://stackoverflow.com/questions/11042027/glpixelstoreigl-unpack-alignment-1-disadvantages) – BDL Jan 10 '23 at 23:04
  • I'm not sure if I understand you correctly: When data is `float*`, then yes, it will always be dividable by 4. It doesn't matter which width you have. If your data is actually 1-byte per channel (RGB8), then the width does matter. But even than it has nothing to do with NPOT/POT sizes. Can you elaborate what data type you actually have and update your question with the full code. Since I don't know how the "problems" manifest is your code, we can't tell you more. – BDL Jan 11 '23 at 10:11
  • Also note, that even if you do have an alignment problem, there would only be non-deterministic data at the end of your texture. Most of the texture has to stay the same in every run. If your whole texture is non-deterministic, then the problem is very likely not an alignment issue. – BDL Jan 11 '23 at 10:13
  • I am aware of that Nicol Bolas post and it is clear and makes sense. I think I included all relevant code. Data are floats that are extracted from that LUT file, where ech row represents R G B vals. So this is what does not make sense to me. As 33(width) * 12 (sizoef(GL_FLOAT) + 3 - cus I have RGB, that is represented by each row of the LUT), so total row size in bytes is: 33 * 12 = 396 using alignment 1, 2, 4 The only one that would differ would be align 8 as with using that then the row length would be 400. – CJ_Notned Jan 11 '23 at 10:37
  • So the only explenation for me is that - somehow the alignment was before set to val. 8 so it was not working properly with 396 row length. The determinism will not occur on just the end, but on the end of each row and because od interpolation you would have affected also surrounding colours. – CJ_Notned Jan 11 '23 at 10:40
  • Yes, thah was the case, I used the `glGetIntegerv(GL_UNPACK_ALIGNMENT, &align);` (don't know why it took my 5 years to find this debug call) to find out something in the system was setting the alignment to 8. So now I understand why it was not originally working. What I still do not understand is, why it was not wroking, when I set the `glPixelStorei(GL_UNPACK_ALIGNMENT, 1);` or to val. 2 though, as row byte size seems to me for all of these other options same: 396. Actually as it is 3D tex. it is 13 068 (33 * 33 * 12), but that changes nothing, as it is dividable also by 1, 2 and also 4. – CJ_Notned Jan 11 '23 at 11:39

1 Answers1

0

So the long story short: the problem was that something somewhere in the rest of the code was setting the GL_UNPACK_ALIGNMENT to 8 (find out using glGetIntegerv(GL_UNPACK_ALIGNMENT, &align)) which was not possible to divide the actual row byte size to get the whole number so the texture was malformed.

As the actual row byte size is 33 * 33 * 12 (width * depth * sizeof(GL_FLOAT) * 3 (RGB)) = 13 068 which is dividible by 1, 2 AND also 4 (so all of these possibilities must be valid if used by image loader) it was revealed in the end that it works for all of these settings and I must missed something (or forget to recompile or whatever when I experienced problems with GL_UNPACK_ALIGNMENT setted to 1 as it is valid option and now I experience it working properly - same with values 2 and 4).

CJ_Notned
  • 248
  • 2
  • 11