Commit 460e41f2 by Alexis Hetu Committed by Alexis Hétu

Handling ETC2, EAC and ASTC related enums

Note that no decoding functionality is added here. This cl merely acknowledges textures of the ETC2, EAC and ASTC format by handling their related enums in SwiftShader, and the byte data is then allowed to be passed down all the way to the Surface object, where the decoding code will be added. Also note that this cl does not add the extensions strings required for ASTC support, so ASTC is still unsupported after this cl. Change-Id: I1d8aed0fb64b0d4c72846e87410750d1e485c46b Reviewed-on: https://swiftshader-review.googlesource.com/3938Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com>
parent 7a57040f
...@@ -24,6 +24,11 @@ ...@@ -24,6 +24,11 @@
namespace namespace
{ {
int getNumBlocks(int w, int h, int blockSizeX, int blockSizeY)
{
return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY);
}
enum DataType enum DataType
{ {
Alpha, Alpha,
...@@ -415,27 +420,99 @@ namespace egl ...@@ -415,27 +420,99 @@ namespace egl
sw::Format SelectInternalFormat(GLenum format, GLenum type) sw::Format SelectInternalFormat(GLenum format, GLenum type)
{ {
if(format == GL_ETC1_RGB8_OES) switch(format)
{ {
case GL_ETC1_RGB8_OES:
return sw::FORMAT_ETC1; return sw::FORMAT_ETC1;
} case GL_COMPRESSED_R11_EAC:
else return sw::FORMAT_R11_EAC;
case GL_COMPRESSED_SIGNED_R11_EAC:
return sw::FORMAT_SIGNED_R11_EAC;
case GL_COMPRESSED_RG11_EAC:
return sw::FORMAT_RG11_EAC;
case GL_COMPRESSED_SIGNED_RG11_EAC:
return sw::FORMAT_SIGNED_RG11_EAC;
case GL_COMPRESSED_RGB8_ETC2:
return sw::FORMAT_RGB8_ETC2;
case GL_COMPRESSED_SRGB8_ETC2:
return sw::FORMAT_SRGB8_ETC2;
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return sw::FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return sw::FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
case GL_COMPRESSED_RGBA8_ETC2_EAC:
return sw::FORMAT_RGBA8_ETC2_EAC;
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
return sw::FORMAT_SRGB8_ALPHA8_ETC2_EAC;
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
return sw::FORMAT_RGBA_ASTC_4x4_KHR;
case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
return sw::FORMAT_RGBA_ASTC_5x4_KHR;
case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
return sw::FORMAT_RGBA_ASTC_5x5_KHR;
case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
return sw::FORMAT_RGBA_ASTC_6x5_KHR;
case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
return sw::FORMAT_RGBA_ASTC_6x6_KHR;
case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
return sw::FORMAT_RGBA_ASTC_8x5_KHR;
case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
return sw::FORMAT_RGBA_ASTC_8x6_KHR;
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
return sw::FORMAT_RGBA_ASTC_8x8_KHR;
case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
return sw::FORMAT_RGBA_ASTC_10x5_KHR;
case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
return sw::FORMAT_RGBA_ASTC_10x6_KHR;
case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
return sw::FORMAT_RGBA_ASTC_10x8_KHR;
case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
return sw::FORMAT_RGBA_ASTC_10x10_KHR;
case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
return sw::FORMAT_RGBA_ASTC_12x10_KHR;
case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
return sw::FORMAT_RGBA_ASTC_12x12_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR;
#if S3TC_SUPPORT #if S3TC_SUPPORT
if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
{ return sw::FORMAT_DXT1;
return sw::FORMAT_DXT1; case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
} return sw::FORMAT_DXT3;
else if(format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE) case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
{ return sw::FORMAT_DXT5;
return sw::FORMAT_DXT3;
}
else if(format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE)
{
return sw::FORMAT_DXT5;
}
else
#endif #endif
default:
break;
}
if(type == GL_FLOAT) if(type == GL_FLOAT)
{ {
return sw::FORMAT_A32B32G32R32F; return sw::FORMAT_A32B32G32R32F;
...@@ -598,14 +675,55 @@ namespace egl ...@@ -598,14 +675,55 @@ namespace egl
case GL_COMPRESSED_SRGB8_ETC2: case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return 8 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f); return 8 * getNumBlocks(width, height, 4, 4);
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
case GL_COMPRESSED_RG11_EAC: case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC: case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGBA8_ETC2_EAC: case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
return 16 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f); case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
return 16 * getNumBlocks(width, height, 4, 4);
case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
return 16 * getNumBlocks(width, height, 5, 4);
case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
return 16 * getNumBlocks(width, height, 5, 5);
case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
return 16 * getNumBlocks(width, height, 6, 5);
case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
return 16 * getNumBlocks(width, height, 6, 6);
case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
return 16 * getNumBlocks(width, height, 8, 5);
case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
return 16 * getNumBlocks(width, height, 8, 6);
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
return 16 * getNumBlocks(width, height, 8, 8);
case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
return 16 * getNumBlocks(width, height, 10, 5);
case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
return 16 * getNumBlocks(width, height, 10, 6);
case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
return 16 * getNumBlocks(width, height, 10, 8);
case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
return 16 * getNumBlocks(width, height, 10, 10);
case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
return 16 * getNumBlocks(width, height, 12, 10);
case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
return 16 * getNumBlocks(width, height, 12, 12);
default: default:
return 0; return 0;
} }
......
...@@ -109,6 +109,34 @@ const GLenum compressedTextureFormats[] = ...@@ -109,6 +109,34 @@ const GLenum compressedTextureFormats[] =
GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
GL_COMPRESSED_RGBA8_ETC2_EAC, GL_COMPRESSED_RGBA8_ETC2_EAC,
GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
GL_COMPRESSED_RGBA_ASTC_4x4_KHR,
GL_COMPRESSED_RGBA_ASTC_5x4_KHR,
GL_COMPRESSED_RGBA_ASTC_5x5_KHR,
GL_COMPRESSED_RGBA_ASTC_6x5_KHR,
GL_COMPRESSED_RGBA_ASTC_6x6_KHR,
GL_COMPRESSED_RGBA_ASTC_8x5_KHR,
GL_COMPRESSED_RGBA_ASTC_8x6_KHR,
GL_COMPRESSED_RGBA_ASTC_8x8_KHR,
GL_COMPRESSED_RGBA_ASTC_10x5_KHR,
GL_COMPRESSED_RGBA_ASTC_10x6_KHR,
GL_COMPRESSED_RGBA_ASTC_10x8_KHR,
GL_COMPRESSED_RGBA_ASTC_10x10_KHR,
GL_COMPRESSED_RGBA_ASTC_12x10_KHR,
GL_COMPRESSED_RGBA_ASTC_12x12_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
#endif #endif
}; };
......
...@@ -293,7 +293,7 @@ GLenum Framebuffer::completeness(int &width, int &height, int &samples) ...@@ -293,7 +293,7 @@ GLenum Framebuffer::completeness(int &width, int &height, int &samples)
{ {
GLenum format = colorbuffer->getFormat(); GLenum format = colorbuffer->getFormat();
if(IsCompressed(format) || if(IsCompressed(format, egl::getClientVersion()) ||
format == GL_ALPHA || format == GL_ALPHA ||
format == GL_LUMINANCE || format == GL_LUMINANCE ||
format == GL_LUMINANCE_ALPHA) format == GL_LUMINANCE_ALPHA)
......
...@@ -428,7 +428,7 @@ void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei widt ...@@ -428,7 +428,7 @@ void Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei widt
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
if(IsCompressed(image->getFormat())) if(IsCompressed(image->getFormat(), egl::getClientVersion()))
{ {
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
} }
...@@ -860,7 +860,7 @@ bool Texture2D::isMipmapComplete() const ...@@ -860,7 +860,7 @@ bool Texture2D::isMipmapComplete() const
bool Texture2D::isCompressed(GLenum target, GLint level) const bool Texture2D::isCompressed(GLenum target, GLint level) const
{ {
return IsCompressed(getFormat(target, level)); return IsCompressed(getFormat(target, level), egl::getClientVersion());
} }
bool Texture2D::isDepth(GLenum target, GLint level) const bool Texture2D::isDepth(GLenum target, GLint level) const
...@@ -1198,7 +1198,7 @@ bool TextureCubeMap::isMipmapCubeComplete() const ...@@ -1198,7 +1198,7 @@ bool TextureCubeMap::isMipmapCubeComplete() const
bool TextureCubeMap::isCompressed(GLenum target, GLint level) const bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
{ {
return IsCompressed(getFormat(target, level)); return IsCompressed(getFormat(target, level), egl::getClientVersion());
} }
bool TextureCubeMap::isDepth(GLenum target, GLint level) const bool TextureCubeMap::isDepth(GLenum target, GLint level) const
...@@ -1766,7 +1766,7 @@ bool Texture3D::isMipmapComplete() const ...@@ -1766,7 +1766,7 @@ bool Texture3D::isMipmapComplete() const
bool Texture3D::isCompressed(GLenum target, GLint level) const bool Texture3D::isCompressed(GLenum target, GLint level) const
{ {
return IsCompressed(getFormat(target, level)); return IsCompressed(getFormat(target, level), egl::getClientVersion());
} }
bool Texture3D::isDepth(GLenum target, GLint level) const bool Texture3D::isDepth(GLenum target, GLint level) const
......
...@@ -131,6 +131,12 @@ static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei heigh ...@@ -131,6 +131,12 @@ static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei heigh
static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat) static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat)
{ {
GLenum formatError = ValidateCompressedFormat(textureFormat, egl::getClientVersion(), false);
if(formatError != GL_NONE)
{
return error(formatError, false);
}
// [OpenGL ES 2.0.24] table 3.9 // [OpenGL ES 2.0.24] table 3.9
switch(textureFormat) switch(textureFormat)
{ {
...@@ -167,20 +173,6 @@ static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFo ...@@ -167,20 +173,6 @@ static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFo
return error(GL_INVALID_OPERATION, false); return error(GL_INVALID_OPERATION, false);
} }
break; break;
case GL_ETC1_RGB8_OES:
return error(GL_INVALID_OPERATION, false);
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(S3TC_SUPPORT)
{
return error(GL_INVALID_OPERATION, false);
}
else
{
return error(GL_INVALID_ENUM, false);
}
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL_OES: case GL_DEPTH_STENCIL_OES:
return error(GL_INVALID_OPERATION, false); return error(GL_INVALID_OPERATION, false);
...@@ -973,36 +965,8 @@ void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLs ...@@ -973,36 +965,8 @@ void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLs
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
egl::GLint clientVersion = egl::getClientVersion();
switch(internalformat) switch(internalformat)
{ {
case GL_ETC1_RGB8_OES:
break;
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
if(clientVersion >= 3)
{
break;
}
return error(GL_INVALID_ENUM);
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(!S3TC_SUPPORT)
{
return error(GL_INVALID_ENUM);
}
break;
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT32_OES: case GL_DEPTH_COMPONENT32_OES:
...@@ -1010,7 +974,14 @@ void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLs ...@@ -1010,7 +974,14 @@ void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLs
case GL_DEPTH24_STENCIL8_OES: case GL_DEPTH24_STENCIL8_OES:
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
default: default:
return error(GL_INVALID_ENUM); {
GLenum formatError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
if(formatError != GL_NONE)
{
return error(formatError);
}
}
break;
} }
if(border != 0) if(border != 0)
...@@ -1116,38 +1087,10 @@ void CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yo ...@@ -1116,38 +1087,10 @@ void CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yo
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
egl::GLint clientVersion = egl::getClientVersion(); GLenum formatError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
if(formatError != GL_NONE)
switch(format)
{ {
case GL_ETC1_RGB8_OES: return error(formatError);
break;
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
if(clientVersion >= 3)
{
break;
}
return error(GL_INVALID_ENUM);
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(!S3TC_SUPPORT)
{
return error(GL_INVALID_ENUM);
}
break;
default:
return error(GL_INVALID_ENUM);
} }
if(width == 0 || height == 0 || data == NULL) if(width == 0 || height == 0 || data == NULL)
...@@ -5143,6 +5086,12 @@ void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, ...@@ -5143,6 +5086,12 @@ void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
} }
} }
GLenum formatError = ValidateCompressedFormat(format, clientVersion, false);
if(formatError != GL_NONE)
{
return error(formatError);
}
switch(format) switch(format)
{ {
case GL_ALPHA: case GL_ALPHA:
...@@ -5755,35 +5704,6 @@ void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, ...@@ -5755,35 +5704,6 @@ void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
return error(GL_INVALID_ENUM); return error(GL_INVALID_ENUM);
} }
break; break;
case GL_ETC1_RGB8_OES:
return error(GL_INVALID_OPERATION);
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
if(clientVersion >= 3)
{
return error(GL_INVALID_OPERATION);
}
return error(GL_INVALID_ENUM);
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(S3TC_SUPPORT)
{
return error(GL_INVALID_OPERATION);
}
else
{
return error(GL_INVALID_ENUM);
}
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
switch(internalformat) switch(internalformat)
{ {
...@@ -7216,17 +7136,6 @@ void CompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, ...@@ -7216,17 +7136,6 @@ void CompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat,
switch(internalformat) switch(internalformat)
{ {
case GL_ETC1_RGB8_OES:
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(!S3TC_SUPPORT)
{
return error(GL_INVALID_ENUM);
}
break;
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT32_OES: case GL_DEPTH_COMPONENT32_OES:
...@@ -7234,7 +7143,13 @@ void CompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, ...@@ -7234,7 +7143,13 @@ void CompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat,
case GL_DEPTH24_STENCIL8_OES: case GL_DEPTH24_STENCIL8_OES:
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
default: default:
return error(GL_INVALID_ENUM); {
GLenum formatError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
if(formatError != GL_NONE)
{
return error(formatError);
}
}
} }
if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth) if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
...@@ -7277,21 +7192,10 @@ void CompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint ...@@ -7277,21 +7192,10 @@ void CompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
switch(format) GLenum formatError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
if(formatError != GL_NONE)
{ {
case GL_ETC1_RGB8_OES: return error(formatError);
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(!S3TC_SUPPORT)
{
return error(GL_INVALID_ENUM);
}
break;
default:
return error(GL_INVALID_ENUM);
} }
if(width == 0 || height == 0 || depth == 0 || data == NULL) if(width == 0 || height == 0 || depth == 0 || data == NULL)
......
...@@ -120,6 +120,12 @@ static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei heigh ...@@ -120,6 +120,12 @@ static bool validateSubImageParams(bool compressed, GLsizei width, GLsizei heigh
static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat) static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat)
{ {
GLenum formatError = ValidateCompressedFormat(textureFormat, egl::getClientVersion(), false);
if(formatError != GL_NONE)
{
return error(formatError, false);
}
switch(textureFormat) switch(textureFormat)
{ {
case GL_ALPHA: case GL_ALPHA:
...@@ -155,30 +161,6 @@ static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFo ...@@ -155,30 +161,6 @@ static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFo
return error(GL_INVALID_OPERATION, false); return error(GL_INVALID_OPERATION, false);
} }
break; break;
case GL_ETC1_RGB8_OES:
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
return error(GL_INVALID_OPERATION, false);
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(S3TC_SUPPORT)
{
return error(GL_INVALID_OPERATION, false);
}
else
{
return error(GL_INVALID_ENUM, false);
}
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL: case GL_DEPTH_STENCIL:
return error(GL_INVALID_OPERATION, false); return error(GL_INVALID_OPERATION, false);
...@@ -899,27 +881,6 @@ GL_APICALL void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, G ...@@ -899,27 +881,6 @@ GL_APICALL void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, G
switch(internalformat) switch(internalformat)
{ {
case GL_ETC1_RGB8_OES:
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(!S3TC_SUPPORT)
{
return error(GL_INVALID_ENUM);
}
break;
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT32_OES: case GL_DEPTH_COMPONENT32_OES:
...@@ -927,7 +888,13 @@ GL_APICALL void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, G ...@@ -927,7 +888,13 @@ GL_APICALL void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, G
case GL_DEPTH24_STENCIL8: case GL_DEPTH24_STENCIL8:
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
default: default:
return error(GL_INVALID_ENUM); {
GLenum formatError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
if(formatError != GL_NONE)
{
return error(formatError);
}
}
} }
if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth) if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
...@@ -971,31 +938,10 @@ GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level ...@@ -971,31 +938,10 @@ GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level
return error(GL_INVALID_VALUE); return error(GL_INVALID_VALUE);
} }
switch(format) GLenum formatError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
if(formatError != GL_NONE)
{ {
case GL_ETC1_RGB8_OES: return error(formatError);
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if(!S3TC_SUPPORT)
{
return error(GL_INVALID_ENUM);
}
break;
default:
return error(GL_INVALID_ENUM);
} }
if(width == 0 || height == 0 || depth == 0 || data == NULL) if(width == 0 || height == 0 || depth == 0 || data == NULL)
......
...@@ -316,23 +316,64 @@ namespace es2 ...@@ -316,23 +316,64 @@ namespace es2
return static_cast<GLint>((static_cast<GLfloat>(0xFFFFFFFF) * value - 1.0f) * 0.5f); return static_cast<GLint>((static_cast<GLfloat>(0xFFFFFFFF) * value - 1.0f) * 0.5f);
} }
bool IsCompressed(GLenum format) bool IsCompressed(GLenum format, egl::GLint clientVersion)
{ {
return format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || return ValidateCompressedFormat(format, clientVersion, true) == GL_NONE;
format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || }
format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE ||
format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE || GLenum ValidateCompressedFormat(GLenum format, egl::GLint clientVersion, bool expectCompressedFormats)
format == GL_ETC1_RGB8_OES || {
format == GL_COMPRESSED_R11_EAC || switch(format)
format == GL_COMPRESSED_SIGNED_R11_EAC || {
format == GL_COMPRESSED_RG11_EAC || case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
format == GL_COMPRESSED_SIGNED_RG11_EAC || case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
format == GL_COMPRESSED_RGB8_ETC2 || case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
format == GL_COMPRESSED_SRGB8_ETC2 || case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
format == GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 || return S3TC_SUPPORT ? (expectCompressedFormats ? GL_NONE : GL_INVALID_OPERATION) : GL_INVALID_ENUM;
format == GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 || case GL_ETC1_RGB8_OES:
format == GL_COMPRESSED_RGBA8_ETC2_EAC || return expectCompressedFormats ? GL_NONE : GL_INVALID_OPERATION;
format == GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
return (clientVersion >= 3) ? (expectCompressedFormats ? GL_NONE : GL_INVALID_OPERATION) : GL_INVALID_ENUM;
default:
return expectCompressedFormats ? GL_INVALID_ENUM : GL_NONE; // Not compressed format
}
} }
bool IsDepthTexture(GLenum format) bool IsDepthTexture(GLenum format)
......
...@@ -40,7 +40,8 @@ namespace es2 ...@@ -40,7 +40,8 @@ namespace es2
GLint floatToInt(GLfloat value); GLint floatToInt(GLfloat value);
bool IsCompressed(GLenum format); bool IsCompressed(GLenum format, egl::GLint clientVersion);
GLenum ValidateCompressedFormat(GLenum format, egl::GLint clientVersion, bool expectCompressedFormats);
bool IsDepthTexture(GLenum format); bool IsDepthTexture(GLenum format);
bool IsStencilTexture(GLenum format); bool IsStencilTexture(GLenum format);
bool IsCubemapTextureTarget(GLenum target); bool IsCubemapTextureTarget(GLenum target);
......
...@@ -77,7 +77,45 @@ namespace sw ...@@ -77,7 +77,45 @@ namespace sw
FORMAT_DXT5, FORMAT_DXT5,
FORMAT_ATI1, FORMAT_ATI1,
FORMAT_ATI2, FORMAT_ATI2,
FORMAT_ETC1, FORMAT_ETC1,
FORMAT_R11_EAC,
FORMAT_SIGNED_R11_EAC,
FORMAT_RG11_EAC,
FORMAT_SIGNED_RG11_EAC,
FORMAT_RGB8_ETC2,
FORMAT_SRGB8_ETC2,
FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
FORMAT_RGBA8_ETC2_EAC,
FORMAT_SRGB8_ALPHA8_ETC2_EAC,
FORMAT_RGBA_ASTC_4x4_KHR,
FORMAT_RGBA_ASTC_5x4_KHR,
FORMAT_RGBA_ASTC_5x5_KHR,
FORMAT_RGBA_ASTC_6x5_KHR,
FORMAT_RGBA_ASTC_6x6_KHR,
FORMAT_RGBA_ASTC_8x5_KHR,
FORMAT_RGBA_ASTC_8x6_KHR,
FORMAT_RGBA_ASTC_8x8_KHR,
FORMAT_RGBA_ASTC_10x5_KHR,
FORMAT_RGBA_ASTC_10x6_KHR,
FORMAT_RGBA_ASTC_10x8_KHR,
FORMAT_RGBA_ASTC_10x10_KHR,
FORMAT_RGBA_ASTC_12x10_KHR,
FORMAT_RGBA_ASTC_12x12_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR,
FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR,
// Floating-point formats // Floating-point formats
FORMAT_A16F, FORMAT_A16F,
FORMAT_R16F, FORMAT_R16F,
...@@ -365,6 +403,9 @@ namespace sw ...@@ -365,6 +403,9 @@ namespace sw
static void decodeATI1(Buffer &internal, const Buffer &external); static void decodeATI1(Buffer &internal, const Buffer &external);
static void decodeATI2(Buffer &internal, const Buffer &external); static void decodeATI2(Buffer &internal, const Buffer &external);
static void decodeETC1(Buffer &internal, const Buffer &external); static void decodeETC1(Buffer &internal, const Buffer &external);
static void decodeEAC(Buffer &internal, const Buffer &external, int nbChannels, bool isSigned);
static void decodeETC2(Buffer &internal, const Buffer &external, int nbAlphaBits, bool isSRGB);
static void decodeASTC(Buffer &internal, const Buffer &external, int xSize, int ySize, int zSize, bool isSRGB);
static void update(Buffer &destination, Buffer &source); static void update(Buffer &destination, Buffer &source);
static void genericUpdate(Buffer &destination, Buffer &source); static void genericUpdate(Buffer &destination, Buffer &source);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment