Fix texture completeness test when using sampler objects.

When a sampler object is bound to a texture unit, it overrides the
texture's filter modes. A texture without mipmaps can thus be complete
even if it has a filter mode which requires mipmaps, if there's a
sampler object with a filter mode which doesn't require mipmaps.

Fixes https://github.com/google/filament/pull/220

Change-Id: I200c0bba467d904ac0fd6d93b935e052c47b2030
Reviewed-on: https://swiftshader-review.googlesource.com/20529
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Jeff McGlynn <jwmcglynn@google.com>
Tested-by: Jeff McGlynn <jwmcglynn@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index 2273e65..584b56d 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -3086,13 +3086,13 @@
 			TextureType textureType = programObject->getSamplerTextureType(samplerType, samplerIndex);
 
 			Texture *texture = getSamplerTexture(textureUnit, textureType);
+			Sampler *samplerObject = mState.sampler[textureUnit];
 
-			if(texture->isSamplerComplete())
+			if(texture->isSamplerComplete(samplerObject))
 			{
 				GLenum wrapS, wrapT, wrapR, minFilter, magFilter, compFunc, compMode;
 				GLfloat minLOD, maxLOD, maxAnisotropy;
 
-				Sampler *samplerObject = mState.sampler[textureUnit];
 				if(samplerObject)
 				{
 					wrapS = samplerObject->getWrapS();
@@ -4372,12 +4372,12 @@
 			return EGL_BAD_ACCESS;
 		}
 
-		if(textureLevel != 0 && !texture->isSamplerComplete())
+		if(textureLevel != 0 && !texture->isSamplerComplete(nullptr))
 		{
 			return EGL_BAD_PARAMETER;
 		}
 
-		if(textureLevel == 0 && !(texture->isSamplerComplete() && texture->getTopLevel() == 0))
+		if(textureLevel == 0 && !(texture->isSamplerComplete(nullptr) && texture->getTopLevel() == 0))
 		{
 			return EGL_BAD_PARAMETER;
 		}
diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index dae52ee..4e63750 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -22,6 +22,7 @@
 #include "mathutil.h"
 #include "Framebuffer.h"
 #include "Device.hpp"
+#include "Sampler.h"
 #include "Shader.h"
 #include "libEGL/Display.h"
 #include "common/Surface.hpp"
@@ -397,9 +398,11 @@
 	return true;
 }
 
-bool Texture::isMipmapFiltered() const
+bool Texture::isMipmapFiltered(Sampler *sampler) const
 {
-	switch(mMinFilter)
+	GLenum minFilter = sampler ? sampler->getMinFilter() : mMinFilter;
+
+	switch(minFilter)
 	{
 	case GL_NEAREST:
 	case GL_LINEAR:
@@ -409,7 +412,7 @@
 	case GL_NEAREST_MIPMAP_LINEAR:
 	case GL_LINEAR_MIPMAP_LINEAR:
 		return true;
-	default: UNREACHABLE(mMinFilter);
+	default: UNREACHABLE(minFilter);
 	}
 
 	return false;
@@ -517,7 +520,6 @@
 
 int Texture2D::getTopLevel() const
 {
-	ASSERT(isSamplerComplete());
 	int level = mBaseLevel;
 
 	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
@@ -702,7 +704,7 @@
 }
 
 // Tests for 2D texture sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
-bool Texture2D::isSamplerComplete() const
+bool Texture2D::isSamplerComplete(Sampler *sampler) const
 {
 	if(!image[mBaseLevel])
 	{
@@ -717,7 +719,7 @@
 		return false;
 	}
 
-	if(isMipmapFiltered())
+	if(isMipmapFiltered(sampler))
 	{
 		if(!isMipmapComplete())
 		{
@@ -1021,7 +1023,6 @@
 
 int TextureCubeMap::getTopLevel() const
 {
-	ASSERT(isSamplerComplete());
 	int level = mBaseLevel;
 
 	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[0][level])
@@ -1078,7 +1079,7 @@
 }
 
 // Tests for cube map sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 161.
-bool TextureCubeMap::isSamplerComplete() const
+bool TextureCubeMap::isSamplerComplete(Sampler *sampler) const
 {
 	for(int face = 0; face < 6; face++)
 	{
@@ -1095,7 +1096,7 @@
 		return false;
 	}
 
-	if(!isMipmapFiltered())
+	if(!isMipmapFiltered(sampler))
 	{
 		if(!isCubeComplete())
 		{
@@ -1545,7 +1546,6 @@
 
 int Texture3D::getTopLevel() const
 {
-	ASSERT(isSamplerComplete());
 	int level = mBaseLevel;
 
 	while(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && image[level])
@@ -1698,7 +1698,7 @@
 }
 
 // Tests for 3D texture sampling completeness. [OpenGL ES 3.0.5] section 3.8.13 page 160.
-bool Texture3D::isSamplerComplete() const
+bool Texture3D::isSamplerComplete(Sampler *sampler) const
 {
 	if(!image[mBaseLevel])
 	{
@@ -1714,7 +1714,7 @@
 		return false;
 	}
 
-	if(isMipmapFiltered())
+	if(isMipmapFiltered(sampler))
 	{
 		if(!isMipmapComplete())
 		{
diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index ddd915e..017acab 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -33,6 +33,8 @@
 
 namespace es2
 {
+class Sampler;
+
 enum
 {
 	IMPLEMENTATION_MAX_TEXTURE_LEVELS = sw::MIPMAP_LEVELS,
@@ -99,7 +101,7 @@
 	virtual int getTopLevel() const = 0;
 	virtual bool requiresSync() const = 0;
 
-	virtual bool isSamplerComplete() const = 0;
+	virtual bool isSamplerComplete(Sampler *sampler) const = 0;
 	virtual bool isCompressed(GLenum target, GLint level) const = 0;
 	virtual bool isDepth(GLenum target, GLint level) const = 0;
 
@@ -121,7 +123,7 @@
 
 	bool copy(egl::Image *source, const sw::SliceRect &sourceRect, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest);
 
-	bool isMipmapFiltered() const;
+	bool isMipmapFiltered(Sampler *sampler) const;
 
 	GLenum mMinFilter;
 	GLenum mMagFilter;
@@ -171,7 +173,7 @@
 
 	void setSharedImage(egl::Image *image);
 
-	bool isSamplerComplete() const override;
+	bool isSamplerComplete(Sampler *sampler) const override;
 	bool isCompressed(GLenum target, GLint level) const override;
 	bool isDepth(GLenum target, GLint level) const override;
 	void bindTexImage(gl::Surface *surface);
@@ -238,7 +240,7 @@
 	void copyImage(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source);
 	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Renderbuffer *source) override;
 
-	bool isSamplerComplete() const override;
+	bool isSamplerComplete(Sampler *sampler) const override;
 	bool isCompressed(GLenum target, GLint level) const override;
 	bool isDepth(GLenum target, GLint level) const override;
 	void releaseTexImage() override;
@@ -301,7 +303,7 @@
 
 	void setSharedImage(egl::Image *image);
 
-	bool isSamplerComplete() const override;
+	bool isSamplerComplete(Sampler *sampler) const override;
 	bool isCompressed(GLenum target, GLint level) const override;
 	bool isDepth(GLenum target, GLint level) const override;
 	void releaseTexImage() override;