Canvases now have OpenGL ES support, updated Texture:setWrap to return false for repeat wrap modes in non-power-of-two textures if OpenGL ES 2 is used and the implementation doesn't have support for repeat on NPOT textures.

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2015-01-20 15:13:59 -04:00
parent 18ab3973e8
commit 8067d42df2
9 changed files with 136 additions and 47 deletions
+1 -1
View File
@@ -95,7 +95,7 @@ public:
virtual void setFilter(const Filter &f) = 0; virtual void setFilter(const Filter &f) = 0;
virtual const Filter &getFilter() const; virtual const Filter &getFilter() const;
virtual void setWrap(const Wrap &w) = 0; virtual bool setWrap(const Wrap &w) = 0;
virtual const Wrap &getWrap() const; virtual const Wrap &getWrap() const;
virtual const Vertex *getVertices() const; virtual const Vertex *getVertices() const;
+77 -21
View File
@@ -571,12 +571,17 @@ bool Canvas::loadVolatile()
convertFormat(format, internalformat, externalformat, textype); convertFormat(format, internalformat, externalformat, textype);
// in GLES2, the internalformat and format params of TexImage have to match.
GLint iformat = (GLint) internalformat;
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
iformat = (GLint) externalformat;
while (glGetError() != GL_NO_ERROR) while (glGetError() != GL_NO_ERROR)
/* Clear the error buffer. */; /* Clear the error buffer. */;
glTexImage2D(GL_TEXTURE_2D, glTexImage2D(GL_TEXTURE_2D,
0, 0,
(GLint) internalformat, iformat,
width, height, width, height,
0, 0,
externalformat, externalformat,
@@ -691,11 +696,24 @@ void Canvas::setFilter(const Texture::Filter &f)
gl.setTextureFilter(filter); gl.setTextureFilter(filter);
} }
void Canvas::setWrap(const Texture::Wrap &w) bool Canvas::setWrap(const Texture::Wrap &w)
{ {
bool success = true;
wrap = w; wrap = w;
if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
{
if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP)
success = false;
// If we only have limited NPOT support then the wrap mode must be CLAMP.
wrap.s = wrap.t = WRAP_CLAMP;
}
gl.bindTexture(texture); gl.bindTexture(texture);
gl.setTextureWrap(wrap); gl.setTextureWrap(wrap);
return success;
} }
GLuint Canvas::getGLTexture() const GLuint Canvas::getGLTexture() const
@@ -738,10 +756,13 @@ void Canvas::setupGrab()
gl.matrices.projection.push_back(Matrix::ortho(0.0, width, 0.0, height)); gl.matrices.projection.push_back(Matrix::ortho(0.0, width, 0.0, height));
// Make sure the correct sRGB setting is used when drawing to the canvas. // Make sure the correct sRGB setting is used when drawing to the canvas.
if (format == FORMAT_SRGB) if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
glEnable(GL_FRAMEBUFFER_SRGB); {
else if (screenHasSRGB) if (format == FORMAT_SRGB)
glDisable(GL_FRAMEBUFFER_SRGB); glEnable(GL_FRAMEBUFFER_SRGB);
else if (screenHasSRGB)
glDisable(GL_FRAMEBUFFER_SRGB);
}
if (msaa_buffer != 0) if (msaa_buffer != 0)
msaa_dirty = true; msaa_dirty = true;
@@ -829,8 +850,11 @@ void Canvas::stopGrab(bool switchingToOtherCanvas)
if (switchingToOtherCanvas) if (switchingToOtherCanvas)
{ {
if (format == FORMAT_SRGB) if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
glDisable(GL_FRAMEBUFFER_SRGB); {
if (format == FORMAT_SRGB)
glDisable(GL_FRAMEBUFFER_SRGB);
}
} }
else else
{ {
@@ -839,10 +863,13 @@ void Canvas::stopGrab(bool switchingToOtherCanvas)
current = nullptr; current = nullptr;
gl.setViewport(systemViewport); gl.setViewport(systemViewport);
if (format == FORMAT_SRGB && !screenHasSRGB) if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
glDisable(GL_FRAMEBUFFER_SRGB); {
else if (format != FORMAT_SRGB && screenHasSRGB) if (format == FORMAT_SRGB && !screenHasSRGB)
glEnable(GL_FRAMEBUFFER_SRGB); glDisable(GL_FRAMEBUFFER_SRGB);
else if (format != FORMAT_SRGB && screenHasSRGB)
glEnable(GL_FRAMEBUFFER_SRGB);
}
} }
} }
@@ -865,7 +892,7 @@ void Canvas::clear(Color c)
// We don't need to worry about multiple FBO attachments or global clear // We don't need to worry about multiple FBO attachments or global clear
// color state when OpenGL 3.0+ is supported. // color state when OpenGL 3.0+ is supported.
if (GLAD_VERSION_3_0) if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
{ {
glClearBufferfv(GL_COLOR, 0, glcolor); glClearBufferfv(GL_COLOR, 0, glcolor);
@@ -1020,7 +1047,11 @@ Canvas::Format Canvas::getSizedFormat(Canvas::Format format)
switch (format) switch (format)
{ {
case FORMAT_NORMAL: case FORMAT_NORMAL:
return FORMAT_RGBA8; // 32-bit render targets don't have guaranteed support on OpenGL ES 2.
if (GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8))
return FORMAT_RGBA4;
else
return FORMAT_RGBA8;
case FORMAT_HDR: case FORMAT_HDR:
return FORMAT_RGBA16F; return FORMAT_RGBA16F;
default: default:
@@ -1055,7 +1086,7 @@ void Canvas::convertFormat(Canvas::Format format, GLenum &internalformat, GLenum
break; break;
case FORMAT_RGB10A2: case FORMAT_RGB10A2:
internalformat = GL_RGB10_A2; internalformat = GL_RGB10_A2;
type = GL_UNSIGNED_INT_10_10_10_2; type = GL_UNSIGNED_INT_2_10_10_10_REV;
break; break;
case FORMAT_RG11B10F: case FORMAT_RG11B10F:
internalformat = GL_R11F_G11F_B10F; internalformat = GL_R11F_G11F_B10F;
@@ -1064,7 +1095,12 @@ void Canvas::convertFormat(Canvas::Format format, GLenum &internalformat, GLenum
break; break;
case FORMAT_RGBA16F: case FORMAT_RGBA16F:
internalformat = GL_RGBA16F; internalformat = GL_RGBA16F;
type = GL_FLOAT; if (GLAD_OES_texture_float)
type = GL_HALF_FLOAT_OES;
else if (GLAD_VERSION_1_0)
type = GL_FLOAT;
else
type = GL_HALF_FLOAT;
break; break;
case FORMAT_RGBA32F: case FORMAT_RGBA32F:
internalformat = GL_RGBA32F; internalformat = GL_RGBA32F;
@@ -1073,6 +1109,8 @@ void Canvas::convertFormat(Canvas::Format format, GLenum &internalformat, GLenum
case FORMAT_SRGB: case FORMAT_SRGB:
internalformat = GL_SRGB8_ALPHA8; internalformat = GL_SRGB8_ALPHA8;
type = GL_UNSIGNED_BYTE; type = GL_UNSIGNED_BYTE;
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
externalformat = GL_SRGB_ALPHA;
break; break;
} }
} }
@@ -1106,7 +1144,7 @@ bool Canvas::isSupported()
bool Canvas::isMultiCanvasSupported() bool Canvas::isMultiCanvasSupported()
{ {
// system must support at least 4 simultanious active canvases. // system must support at least 4 simultaneous active canvases.
return gl.getMaxRenderTargets() >= 4; return gl.getMaxRenderTargets() >= 4;
} }
@@ -1124,24 +1162,38 @@ bool Canvas::isFormatSupported(Canvas::Format format)
switch (format) switch (format)
{ {
case FORMAT_RGBA8: case FORMAT_RGBA8:
supported = GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8;
break;
case FORMAT_RGBA4: case FORMAT_RGBA4:
case FORMAT_RGB5A1: case FORMAT_RGB5A1:
case FORMAT_RGB10A2:
supported = true; supported = true;
break; break;
case FORMAT_RGB565: case FORMAT_RGB565:
supported = GLAD_ES_VERSION_2_0 || GLAD_VERSION_4_2 || GLAD_ARB_ES2_compatibility; supported = GLAD_ES_VERSION_2_0 || GLAD_VERSION_4_2 || GLAD_ARB_ES2_compatibility;
break; break;
case FORMAT_RGB10A2:
supported = GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0;
break;
case FORMAT_RG11B10F: case FORMAT_RG11B10F:
supported = GLAD_VERSION_3_0 || GLAD_EXT_packed_float; supported = GLAD_VERSION_3_0 || GLAD_EXT_packed_float /*|| GLAD_APPLE_color_buffer_packed_float*/;
break; break;
case FORMAT_RGBA16F: case FORMAT_RGBA16F:
if (GLAD_VERSION_1_0)
supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
else if (GLAD_ES_VERSION_2_0)
supported = GLAD_EXT_color_buffer_half_float && (GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float);
break;
case FORMAT_RGBA32F: case FORMAT_RGBA32F:
supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_float; supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
break; break;
case FORMAT_SRGB: case FORMAT_SRGB:
supported = GLAD_VERSION_3_0 || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB) if (GLAD_VERSION_1_0)
&& (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB)); {
supported = GLAD_VERSION_3_0 || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
&& (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB));
}
else
supported = GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB;
break; break;
default: default:
supported = false; supported = false;
@@ -1164,6 +1216,10 @@ bool Canvas::isFormatSupported(Canvas::Format format)
GLenum textype = GL_UNSIGNED_BYTE; GLenum textype = GL_UNSIGNED_BYTE;
convertFormat(format, internalformat, externalformat, textype); convertFormat(format, internalformat, externalformat, textype);
// in GLES2, the internalformat and format params of TexImage have to match.
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
internalformat = externalformat;
GLuint texture = 0; GLuint texture = 0;
glGenTextures(1, &texture); glGenTextures(1, &texture);
gl.bindTexture(texture); gl.bindTexture(texture);
+1 -1
View File
@@ -71,7 +71,7 @@ public:
// Implements Texture. // Implements Texture.
virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky); virtual void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
virtual void setFilter(const Texture::Filter &f); virtual void setFilter(const Texture::Filter &f);
virtual void setWrap(const Texture::Wrap &w); virtual bool setWrap(const Texture::Wrap &w);
virtual GLuint getGLTexture() const; virtual GLuint getGLTexture() const;
virtual void predraw(); virtual void predraw();
+9 -5
View File
@@ -254,12 +254,16 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Set whether drawing converts input from linear -> sRGB colorspace. // Set whether drawing converts input from linear -> sRGB colorspace.
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB) if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
|| GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB)
{ {
if (sRGB) if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
glEnable(GL_FRAMEBUFFER_SRGB); {
else if (sRGB)
glDisable(GL_FRAMEBUFFER_SRGB); glEnable(GL_FRAMEBUFFER_SRGB);
else
glDisable(GL_FRAMEBUFFER_SRGB);
}
} }
else else
sRGB = false; sRGB = false;
+32 -5
View File
@@ -155,12 +155,24 @@ void Image::setFilter(const Texture::Filter &f)
gl.setTextureFilter(filter); gl.setTextureFilter(filter);
} }
void Image::setWrap(const Texture::Wrap &w) bool Image::setWrap(const Texture::Wrap &w)
{ {
bool success = true;
wrap = w; wrap = w;
if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
{
if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP)
success = false;
// If we only have limited NPOT support then the wrap mode must be CLAMP.
wrap.s = wrap.t = WRAP_CLAMP;
}
bind(); bind();
gl.setTextureWrap(w); gl.setTextureWrap(w);
return success;
} }
void Image::setMipmapSharpness(float sharpness) void Image::setMipmapSharpness(float sharpness)
@@ -263,10 +275,18 @@ void Image::loadTextureFromCompressedData()
void Image::loadTextureFromImageData() void Image::loadTextureFromImageData()
{ {
GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8; GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
GLenum format = GL_RGBA;
// in GLES2, the internalformat and format params of TexImage have to match.
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
{
format = flags.sRGB ? GL_SRGB_ALPHA : GL_RGBA;
iformat = format;
}
{ {
love::thread::Lock lock(data->getMutex()); love::thread::Lock lock(data->getMutex());
glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, GL_RGBA, glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, format,
GL_UNSIGNED_BYTE, data->getData()); GL_UNSIGNED_BYTE, data->getData());
} }
@@ -292,14 +312,21 @@ bool Image::loadVolatile()
throw love::Exception("sRGB images are not supported on this system."); throw love::Exception("sRGB images are not supported on this system.");
} }
// NPOT textures don't support mipmapping without full NPOT support.
if (hasLimitedNpot() && (width != next_p2(width) || height != next_p2(height)))
{
flags.mipmaps = false;
filter.mipmap = FILTER_NONE;
}
if (maxMipmapSharpness == 0.0f && GLAD_VERSION_1_4) if (maxMipmapSharpness == 0.0f && GLAD_VERSION_1_4)
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness); glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
glGenTextures(1, &texture); glGenTextures(1, &texture);
gl.bindTexture(texture); gl.bindTexture(texture);
gl.setTextureFilter(filter); setFilter(filter);
gl.setTextureWrap(wrap); setWrap(wrap);
setMipmapSharpness(mipmapSharpness); setMipmapSharpness(mipmapSharpness);
// Use a default texture if the size is too big for the system. // Use a default texture if the size is too big for the system.
@@ -616,7 +643,7 @@ bool Image::hasCompressedTextureSupport(image::CompressedData::Format format, bo
bool Image::hasSRGBSupport() bool Image::hasSRGBSupport()
{ {
return GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB; return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
} }
bool Image::getConstant(const char *in, FlagType &out) bool Image::getConstant(const char *in, FlagType &out)
+1 -1
View File
@@ -108,7 +108,7 @@ public:
virtual GLuint getGLTexture() const; virtual GLuint getGLTexture() const;
virtual void setFilter(const Texture::Filter &f); virtual void setFilter(const Texture::Filter &f);
virtual void setWrap(const Texture::Wrap &w); virtual bool setWrap(const Texture::Wrap &w);
void setMipmapSharpness(float sharpness); void setMipmapSharpness(float sharpness);
float getMipmapSharpness() const; float getMipmapSharpness() const;
+8
View File
@@ -55,6 +55,14 @@ public:
**/ **/
virtual void postdraw() {} virtual void postdraw() {}
/**
* Unextended OpenGL ES 2 doesn't support non-clamp wrap modes or mipmapping
* with non-power-of-two textures.
**/
static bool hasLimitedNpot()
{
return GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot);
}
}; // Texture }; // Texture
+5 -11
View File
@@ -713,26 +713,20 @@ int w_getBlendMode(lua_State *L)
int w_setDefaultFilter(lua_State *L) int w_setDefaultFilter(lua_State *L)
{ {
Texture::FilterMode min; Texture::Filter f;
Texture::FilterMode mag;
const char *minstr = luaL_checkstring(L, 1); const char *minstr = luaL_checkstring(L, 1);
const char *magstr = luaL_optstring(L, 2, minstr); const char *magstr = luaL_optstring(L, 2, minstr);
if (!Texture::getConstant(minstr, min)) if (!Texture::getConstant(minstr, f.min))
return luaL_error(L, "Invalid filter mode: %s", minstr); return luaL_error(L, "Invalid filter mode: %s", minstr);
if (!Texture::getConstant(magstr, mag)) if (!Texture::getConstant(magstr, f.mag))
return luaL_error(L, "Invalid filter mode: %s", magstr); return luaL_error(L, "Invalid filter mode: %s", magstr);
float anisotropy = (float) luaL_optnumber(L, 3, 1.0); f.anisotropy = (float) luaL_optnumber(L, 3, 1.0);
Texture::Filter f;
f.min = min;
f.mag = mag;
f.anisotropy = anisotropy;
instance()->setDefaultFilter(f); instance()->setDefaultFilter(f);
return 0; return 0;
} }
+2 -2
View File
@@ -105,8 +105,8 @@ int w_Texture_setWrap(lua_State *L)
if (!Texture::getConstant(tstr, w.t)) if (!Texture::getConstant(tstr, w.t))
return luaL_error(L, "Invalid wrap mode, %s", tstr); return luaL_error(L, "Invalid wrap mode, %s", tstr);
t->setWrap(w); luax_pushboolean(L, t->setWrap(w));
return 0; return 1;
} }
int w_Texture_getWrap(lua_State *L) int w_Texture_getWrap(lua_State *L)