I have some dds textures will fully generated mipmaps (usually 10 levels). Up to know I was just loading the first base level and I was generating mipmaps using GL.GenerateMipmap(GenerateMipmapTarget.Texture2D)
, which worked perfectly.
Since I already save the mipmap data, I wanted to load them manually to the rest levels instead of calling the -very expensive- callback.
This is the corresponding code
//Upload to GPU
bufferID = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, bufferID);
//Temp Variables
int w = width;
int h = height;
int mm_count = ddsImage.header.dwMipMapCount;
int temp_size = ddsImage.header.dwPitchOrLinearSize;
int offset = 0;
for (int i=0; i < ddsImage.header.dwMipMapCount; i++)
{
if (w == 0 || h == 0)
continue;
byte[] tex_data = new byte[temp_size];
Array.Copy(ddsImage.bdata, offset, tex_data, 0, temp_size);
GL.CompressedTexImage2D(TextureTarget.Texture2D, i, this.pif, w, h, 0, temp_size, tex_data);
//Console.WriteLine(GL.GetError());
offset += temp_size;
temp_size /= 4;
w = w >> 1;
h = h >> 1;
}
Console.WriteLine(GL.GetError());
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureLodBias, -0.2f);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.Repeat);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear);
//GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); //Generate Mipmaps from the base level
//Console.WriteLine(GL.GetError());
int max_level = 0;
GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureMaxLevel, out max_level);
int base_level = 0;
GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureBaseLevel, out base_level);
int maxsize = Math.Max(height, width);
int p = (int) Math.Floor(Math.Log(maxsize, 2)) + base_level;
int q = Math.Min(p, max_level);
#if(DEBUG)
//Get all mipmaps
temp_size = ddsImage.header.dwPitchOrLinearSize;
for (int i = 0; i < q; i++)
{
//Get lowest calculated mipmap
byte[] pixels = new byte[temp_size];
//Save to disk
GL.GetCompressedTexImage(TextureTarget.Texture2D, i, pixels);
File.WriteAllBytes("Temp\\level" + i.ToString(), pixels);
temp_size = Math.Max(temp_size / 4, 16);
}
#endif
ddsImage = null;
ddsImage
is an object that holds dds image information and all the pixel data.
These textures are rendered completely black. If I uncomment the line for the mipmap generation everything works like a charm. Also, when I dump the mipmap levels data they're not corrupt. I have a feeling that I need to somehow tell opengl how many mipmaps I have defined but the big question here is why not even the base level doesn't work. At least this one should have worked.
Ok so it turns out that indeed the texture I create is probably incomplete according to https://www.khronos.org/opengl/wiki/Common_Mistakes#Legacy_Generation
I followed the steps and I found out that I need to set the MAX_LEVEL and BASE_LEVEL parameters BEFORE uploading the texture data and this way it worked like a charm.
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 8);
The value for the max level is supposed to be mips - 1
. For some reason though, the texture is again pitch black when I try to use all the mipmaps of the image. I still haven't tested it thoroughly but I think that I should completely ommit the upload of the 2x2 and 1x1 mipmaps. I'll update the answer if I test this.