From Michael Platings, "On nvidia cards mipmap generation for non-power-of-two textures with
GL_GENERATE_MIPMAP_SGIS is very slow (over half a second for a 720*576 texture). However, glGenerateMipmapEXT() performs well (16ms for the same texture), so I have modified the attached files to use Texture::generateMipmap() if glGenerateMipmapEXT is supported, instead of enabling & disabling GL_GENERATE_MIPMAP_SGIS." Notes, from Robert Osfield, I've tested the out of the previous path using GL_GENERATE_MIPMAP_SGIS and non power of two textures on NVidia 7800GT and Nvidia linux drivers with the image size 720x576 and only get compile times of 56ms, so the above half second speed looks to be a driver bug. With Muchael's changes the cost goes done to less than 5ms, so it's certainly an effective change, even given that Michael's poor expereiences with GL_GENERATE_MIP_SGIS do look to be a driver bug.
This commit is contained in:
@@ -719,7 +719,25 @@ class OSG_EXPORT Texture : public osg::StateAttribute
|
||||
/** Helper method. Sets texture parameters. */
|
||||
void applyTexParameters(GLenum target, State& state) const;
|
||||
|
||||
/** Helper method to generate empty mipmap levels by calling of glGenerateMipmapEXT.
|
||||
/** Returns true if _useHardwareMipMapGeneration is true and either
|
||||
* glGenerateMipmapEXT() or GL_GENERATE_MIPMAP_SGIS are supported. */
|
||||
bool isHardwareMipmapGenerationEnabled(const State& state) const;
|
||||
|
||||
/** Returned by mipmapBeforeTexImage() to indicate what
|
||||
* mipmapAfterTexImage() should do */
|
||||
enum GenerateMipmapMode
|
||||
{
|
||||
GENERATE_MIPMAP_NONE,
|
||||
GENERATE_MIPMAP,
|
||||
GENERATE_MIPMAP_TEX_PARAMETER
|
||||
};
|
||||
|
||||
/** Helper methods to be called before and after calling
|
||||
* gl[Compressed][Copy]Tex[Sub]Image2D to handle generating mipmaps. */
|
||||
GenerateMipmapMode mipmapBeforeTexImage(const State& state, bool hardwareMipmapOn) const;
|
||||
void mipmapAfterTexImage(State& state, GenerateMipmapMode beforeResult) const;
|
||||
|
||||
/** Helper method to generate mipmap levels by calling of glGenerateMipmapEXT.
|
||||
* If it is not supported, then call the virtual allocateMipmap() method */
|
||||
void generateMipmap(State& state) const;
|
||||
|
||||
|
||||
@@ -881,7 +881,7 @@ void Texture::computeRequiredTextureDimensions(State& state, const osg::Image& i
|
||||
inwidth = width;
|
||||
inheight = height;
|
||||
|
||||
bool useHardwareMipMapGeneration = !image.isMipmap() && _useHardwareMipMapGeneration && extensions->isGenerateMipMapSupported();
|
||||
bool useHardwareMipMapGeneration = !image.isMipmap() && isHardwareMipmapGenerationEnabled(state);
|
||||
|
||||
if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipMapGeneration )
|
||||
{
|
||||
@@ -933,8 +933,6 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima
|
||||
// current OpenGL context.
|
||||
const unsigned int contextID = state.getContextID();
|
||||
const Extensions* extensions = getExtensions(contextID,true);
|
||||
|
||||
bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
|
||||
|
||||
// select the internalFormat required for the texture.
|
||||
bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
|
||||
@@ -1035,17 +1033,18 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima
|
||||
pbo = 0;
|
||||
}
|
||||
|
||||
bool useHardwareMipMapGeneration = !image->isMipmap() && _useHardwareMipMapGeneration && generateMipMapSupported;
|
||||
bool useHardwareMipMapGeneration = !image->isMipmap() && isHardwareMipmapGenerationEnabled(state);
|
||||
|
||||
if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipMapGeneration)
|
||||
{
|
||||
bool hardwareMipMapOn = false;
|
||||
if (_min_filter != LINEAR && _min_filter != NEAREST)
|
||||
|
||||
if (_min_filter == LINEAR || _min_filter == NEAREST)
|
||||
{
|
||||
if (useHardwareMipMapGeneration) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
|
||||
hardwareMipMapOn = true;
|
||||
useHardwareMipMapGeneration = false;
|
||||
}
|
||||
|
||||
GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
|
||||
|
||||
if ( !compressed_image)
|
||||
{
|
||||
numMipmapLevels = 1;
|
||||
@@ -1070,7 +1069,7 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima
|
||||
data-dataMinusOffset+dataPlusOffset);
|
||||
}
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
|
||||
mipmapAfterTexImage(state, mipmapResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1219,8 +1218,6 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image*
|
||||
// current OpenGL context.
|
||||
const unsigned int contextID = state.getContextID();
|
||||
const Extensions* extensions = getExtensions(contextID,true);
|
||||
|
||||
bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
|
||||
|
||||
// select the internalFormat required for the texture.
|
||||
bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
|
||||
@@ -1267,7 +1264,7 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image*
|
||||
|
||||
}
|
||||
|
||||
bool useHardwareMipMapGeneration = !image->isMipmap() && _useHardwareMipMapGeneration && generateMipMapSupported;
|
||||
bool useHardwareMipMapGeneration = !image->isMipmap() && isHardwareMipmapGenerationEnabled(state);
|
||||
|
||||
unsigned char* dataMinusOffset=0;
|
||||
unsigned char* dataPlusOffset=0;
|
||||
@@ -1290,13 +1287,9 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image*
|
||||
if( _min_filter == LINEAR || _min_filter == NEAREST || useHardwareMipMapGeneration)
|
||||
{
|
||||
|
||||
bool hardwareMipMapOn = false;
|
||||
if (_min_filter != LINEAR && _min_filter != NEAREST)
|
||||
{
|
||||
if (useHardwareMipMapGeneration) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
|
||||
hardwareMipMapOn = true;
|
||||
}
|
||||
|
||||
bool hardwareMipMapOn = _min_filter != LINEAR && _min_filter != NEAREST;
|
||||
|
||||
GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, hardwareMipMapOn);
|
||||
|
||||
if (!compressed_image)
|
||||
{
|
||||
@@ -1321,7 +1314,7 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image*
|
||||
data - dataMinusOffset + dataPlusOffset );
|
||||
}
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
|
||||
mipmapAfterTexImage(state, mipmapResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1405,6 +1398,62 @@ void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image*
|
||||
}
|
||||
}
|
||||
|
||||
bool Texture::isHardwareMipmapGenerationEnabled(const State& state) const
|
||||
{
|
||||
if (_useHardwareMipMapGeneration)
|
||||
{
|
||||
unsigned int contextID = state.getContextID();
|
||||
const Extensions* extensions = getExtensions(contextID,true);
|
||||
|
||||
if (extensions->isGenerateMipMapSupported())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const FBOExtensions* fbo_ext = FBOExtensions::instance(contextID,true);
|
||||
|
||||
if (fbo_ext->glGenerateMipmapEXT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Texture::GenerateMipmapMode Texture::mipmapBeforeTexImage(const State& state, bool hardwareMipmapOn) const
|
||||
{
|
||||
if (hardwareMipmapOn)
|
||||
{
|
||||
//GL_GENERATE_MIPMAP_SGIS with non-power-of-two textures on NVIDIA hardware
|
||||
//is extremely slow. Use glGenerateMipmapEXT() instead if supported.
|
||||
if (_internalFormatType != SIGNED_INTEGER &&
|
||||
_internalFormatType != UNSIGNED_INTEGER &&
|
||||
FBOExtensions::instance(state.getContextID(), true)->glGenerateMipmapEXT)
|
||||
{
|
||||
return GENERATE_MIPMAP;
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
|
||||
return GENERATE_MIPMAP_TEX_PARAMETER;
|
||||
}
|
||||
}
|
||||
return GENERATE_MIPMAP_NONE;
|
||||
}
|
||||
|
||||
void Texture::mipmapAfterTexImage(State& state, GenerateMipmapMode beforeResult) const
|
||||
{
|
||||
switch (beforeResult)
|
||||
{
|
||||
case GENERATE_MIPMAP:
|
||||
generateMipmap(state);
|
||||
break;
|
||||
case GENERATE_MIPMAP_TEX_PARAMETER:
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::generateMipmap(State& state) const
|
||||
{
|
||||
@@ -1432,6 +1481,9 @@ void Texture::generateMipmap(State& state) const
|
||||
if (fbo_ext->glGenerateMipmapEXT)
|
||||
{
|
||||
textureObject->bind();
|
||||
|
||||
// osg::notify(osg::NOTICE)<<"Using generate glGenerateMipmap"<<std::endl;
|
||||
|
||||
fbo_ext->glGenerateMipmapEXT(textureObject->_target);
|
||||
|
||||
// inform state that this texture is the current one bound.
|
||||
@@ -1455,7 +1507,12 @@ void Texture::generateMipmap(State& state) const
|
||||
|
||||
void Texture::compileGLObjects(State& state) const
|
||||
{
|
||||
// osg::Timer_t startTick = osg::Timer::instance()->tick();
|
||||
|
||||
apply(state);
|
||||
|
||||
// osg::Timer_t endTick = osg::Timer::instance()->tick();
|
||||
// osg::notify(osg::NOTICE)<<"compile time = "<<osg::Timer::instance()->delta_m(startTick, endTick)<<std::endl;;
|
||||
}
|
||||
|
||||
void Texture::resizeGLObjectBuffers(unsigned int maxSize)
|
||||
|
||||
@@ -311,25 +311,21 @@ void Texture2D::copyTexImage2D(State& state, int x, int y, int width, int height
|
||||
bool hardwareMipMapOn = false;
|
||||
if (needHardwareMipMap)
|
||||
{
|
||||
const Extensions* extensions = getExtensions(contextID,true);
|
||||
bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
|
||||
|
||||
hardwareMipMapOn = _useHardwareMipMapGeneration && generateMipMapSupported;
|
||||
hardwareMipMapOn = isHardwareMipmapGenerationEnabled(state);
|
||||
|
||||
if (!hardwareMipMapOn)
|
||||
{
|
||||
// have to swtich off mip mapping
|
||||
notify(NOTICE)<<"Warning: Texture2D::copyTexImage2D(,,,,) switch of mip mapping as hardware support not available."<<std::endl;
|
||||
// have to switch off mip mapping
|
||||
notify(NOTICE)<<"Warning: Texture2D::copyTexImage2D(,,,,) switch off mip mapping as hardware support not available."<<std::endl;
|
||||
_min_filter = LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
|
||||
GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, hardwareMipMapOn);
|
||||
|
||||
glCopyTexImage2D( GL_TEXTURE_2D, 0, _internalFormat, x, y, width, height, 0 );
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
|
||||
|
||||
mipmapAfterTexImage(state, mipmapResult);
|
||||
|
||||
_textureWidth = width;
|
||||
_textureHeight = height;
|
||||
@@ -362,24 +358,21 @@ void Texture2D::copyTexSubImage2D(State& state, int xoffset, int yoffset, int x,
|
||||
bool hardwareMipMapOn = false;
|
||||
if (needHardwareMipMap)
|
||||
{
|
||||
const Extensions* extensions = getExtensions(contextID,true);
|
||||
bool generateMipMapSupported = extensions->isGenerateMipMapSupported();
|
||||
|
||||
hardwareMipMapOn = _useHardwareMipMapGeneration && generateMipMapSupported;
|
||||
hardwareMipMapOn = isHardwareMipmapGenerationEnabled(state);
|
||||
|
||||
if (!hardwareMipMapOn)
|
||||
{
|
||||
// have to swtich off mip mapping
|
||||
notify(NOTICE)<<"Warning: Texture2D::copyTexImage2D(,,,,) switch of mip mapping as hardware support not available."<<std::endl;
|
||||
// have to switch off mip mapping
|
||||
notify(NOTICE)<<"Warning: Texture2D::copyTexImage2D(,,,,) switch off mip mapping as hardware support not available."<<std::endl;
|
||||
_min_filter = LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
|
||||
GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, hardwareMipMapOn);
|
||||
|
||||
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height);
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
|
||||
mipmapAfterTexImage(state, mipmapResult);
|
||||
|
||||
// inform state that this texture is the current one bound.
|
||||
state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
|
||||
|
||||
@@ -344,24 +344,21 @@ void TextureCubeMap::copyTexSubImageCubeMap(State& state, int face, int xoffset,
|
||||
bool hardwareMipMapOn = false;
|
||||
if (needHardwareMipMap)
|
||||
{
|
||||
const Texture::Extensions* tex_extensions = Texture::getExtensions(contextID,true);
|
||||
bool generateMipMapSupported = tex_extensions->isGenerateMipMapSupported();
|
||||
|
||||
hardwareMipMapOn = _useHardwareMipMapGeneration && generateMipMapSupported;
|
||||
hardwareMipMapOn = isHardwareMipmapGenerationEnabled(state);
|
||||
|
||||
if (!hardwareMipMapOn)
|
||||
{
|
||||
// have to swtich off mip mapping
|
||||
notify(NOTICE)<<"Warning: TextureCubeMap::copyTexImage2D(,,,,) switch of mip mapping as hardware support not available."<<std::endl;
|
||||
// have to switch off mip mapping
|
||||
notify(NOTICE)<<"Warning: TextureCubeMap::copyTexImage2D(,,,,) switch off mip mapping as hardware support not available."<<std::endl;
|
||||
_min_filter = LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri( target, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
|
||||
GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, hardwareMipMapOn);
|
||||
|
||||
glCopyTexSubImage2D( target , 0, xoffset, yoffset, x, y, width, height);
|
||||
|
||||
if (hardwareMipMapOn) glTexParameteri( target, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
|
||||
mipmapAfterTexImage(state, mipmapResult);
|
||||
|
||||
// inform state that this texture is the current one bound.
|
||||
state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
|
||||
|
||||
Reference in New Issue
Block a user