mirror of
https://github.com/love2d/love.git
synced 2026-08-17 11:00:31 +02:00
Worked around ATI/AMD driver bugs when creating mipmaps for Images
This commit is contained in:
@@ -37,7 +37,8 @@ Image::Image(love::image::ImageData *data)
|
|||||||
: width((float)(data->getWidth()))
|
: width((float)(data->getWidth()))
|
||||||
, height((float)(data->getHeight()))
|
, height((float)(data->getHeight()))
|
||||||
, texture(0)
|
, texture(0)
|
||||||
, mipmapsharpness(0.0f)
|
, mipmapSharpness(0.0f)
|
||||||
|
, mipmapsCreated(false)
|
||||||
{
|
{
|
||||||
data->retain();
|
data->retain();
|
||||||
this->data = data;
|
this->data = data;
|
||||||
@@ -143,36 +144,55 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo
|
|||||||
drawv(t, v);
|
drawv(t, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::checkMipmapsCreated() const
|
void Image::checkMipmapsCreated()
|
||||||
{
|
{
|
||||||
if (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR)
|
if (mipmapsCreated || (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!hasMipmapSupport())
|
if (!hasMipmapSupport())
|
||||||
throw love::Exception("Mipmap filtering is not supported on this system!");
|
throw love::Exception("Mipmap filtering is not supported on this system.");
|
||||||
|
|
||||||
// some old GPUs/systems claim support for NPOT textures, but fail when generating mipmaps
|
// Some old drivers claim support for NPOT textures, but fail when creating mipmaps.
|
||||||
// we can't detect which systems will do this, so we fail gracefully for all NPOT images
|
// we can't detect which systems will do this, so we fail gracefully for all NPOT images.
|
||||||
int w = int(width), h = int(height);
|
int w = int(width), h = int(height);
|
||||||
if (w != next_p2(w) || h != next_p2(h))
|
if (w != next_p2(w) || h != next_p2(h))
|
||||||
throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!");
|
throw love::Exception("Could not create mipmaps: image does not have power of two dimensions.");
|
||||||
|
|
||||||
bind();
|
bind();
|
||||||
|
|
||||||
GLint mipmapscreated;
|
if (hasNpot() && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object))
|
||||||
glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, &mipmapscreated);
|
{
|
||||||
|
// AMD/ATI drivers have several bugs when generating mipmaps,
|
||||||
|
// re-uploading the entire base image seems to be required.
|
||||||
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
|
0,
|
||||||
|
GL_RGBA8,
|
||||||
|
(GLsizei)width,
|
||||||
|
(GLsizei)height,
|
||||||
|
0,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
data->getData());
|
||||||
|
|
||||||
// generate mipmaps for this image if we haven't already
|
// More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
|
||||||
if (!mipmapscreated)
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D,
|
||||||
if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)
|
0,
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
0,
|
||||||
else
|
0,
|
||||||
// modify single texel to trigger mipmap chain generation
|
(GLsizei)width,
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data->getData());
|
(GLsizei)height,
|
||||||
|
GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
data->getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mipmapsCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::setFilter(const Image::Filter &f)
|
void Image::setFilter(const Image::Filter &f)
|
||||||
@@ -180,8 +200,8 @@ void Image::setFilter(const Image::Filter &f)
|
|||||||
filter = f;
|
filter = f;
|
||||||
|
|
||||||
bind();
|
bind();
|
||||||
checkMipmapsCreated();
|
|
||||||
setTextureFilter(f);
|
setTextureFilter(f);
|
||||||
|
checkMipmapsCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Image::Filter &Image::getFilter() const
|
const Image::Filter &Image::getFilter() const
|
||||||
@@ -208,15 +228,15 @@ void Image::setMipmapSharpness(float sharpness)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// LOD bias has the range (-maxbias, maxbias)
|
// LOD bias has the range (-maxbias, maxbias)
|
||||||
mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f);
|
mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f);
|
||||||
|
|
||||||
bind();
|
bind();
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper
|
||||||
}
|
}
|
||||||
|
|
||||||
float Image::getMipmapSharpness() const
|
float Image::getMipmapSharpness() const
|
||||||
{
|
{
|
||||||
return mipmapsharpness;
|
return mipmapSharpness;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::bind() const
|
void Image::bind() const
|
||||||
@@ -240,7 +260,7 @@ void Image::unload()
|
|||||||
bool Image::loadVolatile()
|
bool Image::loadVolatile()
|
||||||
{
|
{
|
||||||
if (hasMipmapSharpnessSupport())
|
if (hasMipmapSharpnessSupport())
|
||||||
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
|
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
|
||||||
|
|
||||||
if (hasNpot())
|
if (hasNpot())
|
||||||
return loadVolatileNPOT();
|
return loadVolatileNPOT();
|
||||||
@@ -253,11 +273,8 @@ bool Image::loadVolatilePOT()
|
|||||||
glGenTextures(1,(GLuint *)&texture);
|
glGenTextures(1,(GLuint *)&texture);
|
||||||
bindTexture(texture);
|
bindTexture(texture);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
setTextureFilter(filter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
setTextureWrap(wrap);
|
||||||
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
float p2width = next_p2(width);
|
float p2width = next_p2(width);
|
||||||
float p2height = next_p2(height);
|
float p2height = next_p2(height);
|
||||||
@@ -289,9 +306,9 @@ bool Image::loadVolatilePOT()
|
|||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
data->getData());
|
data->getData());
|
||||||
|
|
||||||
setMipmapSharpness(mipmapsharpness);
|
mipmapsCreated = false;
|
||||||
setFilter(filter);
|
checkMipmapsCreated();
|
||||||
setWrap(wrap);
|
setMipmapSharpness(mipmapSharpness);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -301,11 +318,8 @@ bool Image::loadVolatileNPOT()
|
|||||||
glGenTextures(1,(GLuint *)&texture);
|
glGenTextures(1,(GLuint *)&texture);
|
||||||
bindTexture(texture);
|
bindTexture(texture);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
setTextureFilter(filter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
setTextureWrap(wrap);
|
||||||
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
@@ -317,9 +331,9 @@ bool Image::loadVolatileNPOT()
|
|||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
data->getData());
|
data->getData());
|
||||||
|
|
||||||
setMipmapSharpness(mipmapsharpness);
|
mipmapsCreated = false;
|
||||||
setFilter(filter);
|
checkMipmapsCreated();
|
||||||
setWrap(wrap);
|
setMipmapSharpness(mipmapSharpness);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -360,12 +374,12 @@ bool Image::hasNpot()
|
|||||||
|
|
||||||
bool Image::hasMipmapSupport()
|
bool Image::hasMipmapSupport()
|
||||||
{
|
{
|
||||||
return (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap) != 0;
|
return GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::hasMipmapSharpnessSupport()
|
bool Image::hasMipmapSharpnessSupport()
|
||||||
{
|
{
|
||||||
return (GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias) != 0;
|
return GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // opengl
|
} // opengl
|
||||||
|
|||||||
@@ -142,11 +142,14 @@ private:
|
|||||||
// The source vertices of the image.
|
// The source vertices of the image.
|
||||||
vertex vertices[4];
|
vertex vertices[4];
|
||||||
|
|
||||||
// Mipmap texture LOD bias value
|
// Mipmap texture LOD bias (sharpness) value.
|
||||||
float mipmapsharpness;
|
float mipmapSharpness;
|
||||||
|
|
||||||
// Implementation-dependent maximum/minimum mipmap sharpness values
|
// Implementation-dependent min/max mipmap sharpness values.
|
||||||
float maxmipmapsharpness;
|
float maxMipmapSharpness;
|
||||||
|
|
||||||
|
// True if mipmaps have been created for this Image.
|
||||||
|
bool mipmapsCreated;
|
||||||
|
|
||||||
// The image's filter mode
|
// The image's filter mode
|
||||||
Image::Filter filter;
|
Image::Filter filter;
|
||||||
@@ -157,7 +160,7 @@ private:
|
|||||||
bool loadVolatilePOT();
|
bool loadVolatilePOT();
|
||||||
bool loadVolatileNPOT();
|
bool loadVolatileNPOT();
|
||||||
|
|
||||||
void checkMipmapsCreated() const;
|
void checkMipmapsCreated();
|
||||||
|
|
||||||
}; // Image
|
}; // Image
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user