Using
glTexStorage2D(GL_TEXTURE_2D, num_mipmaps, GL_RGBA8, width, height);
followed by
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
we can ask OpenGL to generate storage for the first num_mipmaps
many mipmaps levels, and to compute and store those mipmaps. The width and height need not be a power of 2.
According to this:
Khronos webpage on Texture Storage
the dimensions of each new mipmap level are computed by halving corresponding dimension of the previous level, and rounding down, and that this process stops when all dimensions are 1.
It seems to me that if this were 100% literally what happens, then in some cases we might actually reach an image one of whose dimensions was 1, and the other of which was greater than 1. If we were to halve and round down once more, then the smaller dimension would become 0. Is it more accurate to say that the function mapping a given dimension of the current level to the corresponding dimension of the next level, is actually \begin{equation} f(x) = \max(\lfloor x/2 \rfloor), 1) \end{equation} where $\lfloor \cdot \rfloor$ denotes the floor function ?
Since I am using automatic mipmap storage generation, I suppose that I do not need these two calls:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
at least, so it seems according to this:
Khronos webpage on common mistakes
EDIT 1
If indeed the dimensions were clamped below to 1, then I suppose that the function for computing the number of distinct mipmap levels would be \begin{equation} f(w, h) = \lfloor \log_2(\max(w, h)) \rfloor \end{equation} or else \begin{equation} f(w, h) = \lfloor \log_2(\min(w, h)) \rfloor \end{equation} but the language on the Khronos website seems to suggest it's the former, which would also make more sense, since one might have a triangle whose projection into texture space was very long and thin, and whose projection onto the screen occupied only a single pixel.
EDIT 2
Whatever the answer to my question, a separate question is whether I need to set glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, f(w, h));
or whether the use of glGenerateMipmap(GL_TEXTURE_2D);
takes care of this automatically.