Created attachment 143513 [details] Test project Trying to get an average of the pixels I rendered in the scene, I've come across a problem with the way Mesa's implementation of glGenerateMipmap works with NPOT textures. To estimate the average, I render the scene to an FBO texture, and then use the following C++ code (full compilable test project is attached to this bug report): // BEGIN code void getMeanPixelValue(int texW, int texH) { // Get average value of the rendered pixels as the value of the deepest mipmap level glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texFBO); glGenerateMipmap(GL_TEXTURE_2D); using namespace std; // Formula from the glspec, "Mipmapping" subsection in section 3.8.11 Texture Minification const auto totalMipmapLevels = 1+floor(log2(max(texW,texH))); const auto deepestLevel=totalMipmapLevels-1; // Sanity check int deepestMipmapLevelWidth=-1, deepestMipmapLevelHeight=-1; glGetTexLevelParameteriv(GL_TEXTURE_2D, deepestLevel, GL_TEXTURE_WIDTH, &deepestMipmapLevelWidth); glGetTexLevelParameteriv(GL_TEXTURE_2D, deepestLevel, GL_TEXTURE_HEIGHT, &deepestMipmapLevelHeight); assert(deepestMipmapLevelWidth==1); assert(deepestMipmapLevelHeight==1); vec4 pixel; glGetTexImage(GL_TEXTURE_2D, deepestLevel, GL_RGBA, GL_FLOAT, &pixel[0]); // Get average value in an actual summing loop over all the pixels std::vector<vec4> data(texW*texH); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data.data()); vec4 avg(0,0,0,0); for(auto const& v : data) avg+=v; avg/=texW*texH; std::cerr << "Mipmap value: " << pixel[0] << ", " << pixel[1] << ", " << pixel[2] << ", " << pixel[3] << "\n"; std::cerr << "True average: " << avg[0] << ", " << avg[1] << ", " << avg[2] << ", " << avg[3] << "\n"; } // END code What I get from this code on Mesa Software renderer (using LIBGL_ALWAYS_SOFTWARE=1): New size: 512x512 Mipmap value: 0.195312, 0.390625, 0.585938, 0.78125 True average: 0.195312, 0.390625, 0.585938, 0.78125 New size: 512x511 Mipmap value: 0, 1.19209e-07, 1, 1 True average: 0.195695, 0.391389, 0.587084, 0.782779 With Intel Haswell (Core i7-4765T) hardware acceleration, the 1.19209e-07 value becomes simply 0. For comparison, below is what I get on an NVidia GPU with the proprietary "nvidia" driver. This is what I would expect from Mesa and any other decent OpenGL implementation. New size: 512x512 Mipmap value: 0.195312, 0.390625, 0.585938, 0.78125 True average: 0.195312, 0.390625, 0.585938, 0.78125 New size: 512x511 Mipmap value: 0.195606, 0.39101, 0.586946, 0.782537 True average: 0.195695, 0.391389, 0.587084, 0.782779
This sounds like an interesting issue (although I'm pretty sure it doesn't qualify as a bug). GL states that "The contents of the derived images are computed by repeated, filtered reduction of the levelbase image. No particular filter algorithm is required, though a box filter is recommended as the default filter." I believe this is generally how all drivers in mesa implement this (they don't all use the same helpers for it, but I think all end up in a blit with bilinear filter essentially). But you are quite right that the results won't be all that great for npot textures - not even all src texels will be actually considered in the filter (e.g. from a 3x3 to a 1x1 mipmap, only 4 of the 9 texels will actually be used). So presumably a different (more complex, maybe bicubic or even more advanced one) filter used for generating npot mipmaps, at least for mips which round the size down from the next higher up level, could give better results. I have no idea though what kind of filter nvidia uses (and I would not be surprised if other non-mesa blob drivers also simply use bilinear filtering).
(In reply to Roland Scheidegger from comment #1) > I have no idea though what kind of filter nvidia uses (and I would not be > surprised if other non-mesa blob drivers also simply use bilinear filtering). I think they use something like they describe in their paper "Non-Power-of-Two Mipmapping": http://download.nvidia.com/developer/Papers/2005/NP2_Mipmapping/NP2_Mipmap_Creation.pdf
(In reply to Ruslan Kabatsayev from comment #2) > (In reply to Roland Scheidegger from comment #1) > > I have no idea though what kind of filter nvidia uses (and I would not be > > surprised if other non-mesa blob drivers also simply use bilinear filtering). > > I think they use something like they describe in their paper > "Non-Power-of-Two Mipmapping": > > http://download.nvidia.com/developer/Papers/2005/NP2_Mipmapping/ > NP2_Mipmap_Creation.pdf Ah yes that would make sense (although I highly doubt you'd want to do the two-pass approach with the hw of today...). So I guess nvidia is using this approach since ages, interesting. All the apis kind of seemed to have ignored the issues with the box filter with npot textures.
-- GitLab Migration Automatic Message -- This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/mesa/mesa/issues/1037.
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.