diff --git a/include/GLES2/gl2ext_angle.h b/include/GLES2/gl2ext_angle.h index 0683c946d..ae6acceb1 100644 --- a/include/GLES2/gl2ext_angle.h +++ b/include/GLES2/gl2ext_angle.h @@ -537,6 +537,14 @@ GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewSideBySideANGLE(GLenum #endif #endif /* GL_ANGLE_multiview */ +#ifndef GL_ANGLE_texture_rectangle +#define GL_ANGLE_texture_rectangle 1 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE 0x84F8 +#define GL_TEXTURE_RECTANGLE_ANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_ANGLE 0x84F6 +#define GL_SAMPLER_2D_RECT_ANGLE 0x8B63 +#endif /* GL_ANGLE_texture_rectangle */ + // clang-format on #endif // INCLUDE_GLES2_GL2EXT_ANGLE_H_ diff --git a/include/angle_gl.h b/include/angle_gl.h index 18de80b60..b70a31c27 100644 --- a/include/angle_gl.h +++ b/include/angle_gl.h @@ -16,9 +16,4 @@ #include "GLES3/gl31.h" #include "GLES3/gl32.h" -// The following enum is used in ANGLE, but is from desktop GL -#ifndef GL_SAMPLER_2D_RECT_ARB -#define GL_SAMPLER_2D_RECT_ARB 0x8B63 -#endif - #endif // ANGLEGL_H_ diff --git a/src/common/utilities.cpp b/src/common/utilities.cpp index 156bbfb20..427e55e7e 100644 --- a/src/common/utilities.cpp +++ b/src/common/utilities.cpp @@ -124,6 +124,7 @@ GLenum VariableComponentType(GLenum type) return GL_FLOAT; case GL_INT: case GL_SAMPLER_2D: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_SAMPLER_3D: case GL_SAMPLER_CUBE: case GL_SAMPLER_2D_ARRAY: @@ -251,7 +252,7 @@ int VariableRowCount(GLenum type) case GL_SAMPLER_CUBE: case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_EXTERNAL_OES: - case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_SAMPLER_2D_MULTISAMPLE: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: @@ -321,7 +322,7 @@ int VariableColumnCount(GLenum type) case GL_INT_SAMPLER_2D_ARRAY: case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_EXTERNAL_OES: - case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: @@ -385,6 +386,7 @@ bool IsSamplerType(GLenum type) case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_EXTERNAL_OES: case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: @@ -471,6 +473,9 @@ GLenum SamplerTypeToTextureType(GLenum samplerType) case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return GL_TEXTURE_2D_MULTISAMPLE; + case GL_SAMPLER_2D_RECT_ANGLE: + return GL_TEXTURE_RECTANGLE_ANGLE; + default: UNREACHABLE(); return 0; @@ -694,7 +699,7 @@ int VariableSortOrder(GLenum type) case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: case GL_SAMPLER_EXTERNAL_OES: - case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_RECT_ANGLE: case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_3D: diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp index 32ed12867..2336a7bfe 100644 --- a/src/compiler/translator/util.cpp +++ b/src/compiler/translator/util.cpp @@ -332,7 +332,7 @@ GLenum GLVariableType(const TType &type) case EbtSamplerExternal2DY2YEXT: return GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT; case EbtSampler2DRect: - return GL_SAMPLER_2D_RECT_ARB; + return GL_SAMPLER_2D_RECT_ANGLE; case EbtSampler2DArray: return GL_SAMPLER_2D_ARRAY; case EbtSampler2DMS: diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp index 8b159f639..67d53e5ed 100644 --- a/src/libANGLE/Caps.cpp +++ b/src/libANGLE/Caps.cpp @@ -229,7 +229,8 @@ Extensions::Extensions() surfacelessContext(false), clientArrays(false), robustResourceInitialization(false), - programCacheControl(false) + programCacheControl(false), + textureRectangle(false) { } @@ -699,6 +700,7 @@ const ExtensionInfoMap &GetExtensionInfoMap() map["GL_ANGLE_client_arrays"] = esOnlyExtension(&Extensions::clientArrays); map["GL_ANGLE_robust_resource_initialization"] = esOnlyExtension(&Extensions::robustResourceInitialization); map["GL_ANGLE_program_cache_control"] = esOnlyExtension(&Extensions::programCacheControl); + map["GL_ANGLE_texture_rectangle"] = enableableExtension(&Extensions::textureRectangle); // clang-format on return map; @@ -746,6 +748,7 @@ Caps::Caps() : maxElementIndex(0), max3DTextureSize(0), max2DTextureSize(0), + maxRectangleTextureSize(0), maxArrayTextureLayers(0), maxLODBias(0), maxCubeMapTextureSize(0), diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h index 67dbbeb70..797a24975 100644 --- a/src/libANGLE/Caps.h +++ b/src/libANGLE/Caps.h @@ -370,6 +370,9 @@ struct Extensions // GL_ANGLE_program_cache_control bool programCacheControl; + + // GL_ANGLE_texture_rectangle + bool textureRectangle; }; struct ExtensionInfo @@ -432,6 +435,7 @@ struct Caps GLuint64 maxElementIndex; GLuint max3DTextureSize; GLuint max2DTextureSize; + GLuint maxRectangleTextureSize; GLuint maxArrayTextureLayers; GLfloat maxLODBias; GLuint maxCubeMapTextureSize; diff --git a/src/libANGLE/Compiler.cpp b/src/libANGLE/Compiler.cpp index 30af05bcb..430cb7947 100644 --- a/src/libANGLE/Compiler.cpp +++ b/src/libANGLE/Compiler.cpp @@ -72,6 +72,7 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state) mResources.OES_EGL_image_external = extensions.eglImageExternal; mResources.OES_EGL_image_external_essl3 = extensions.eglImageExternalEssl3; mResources.NV_EGL_stream_consumer_external = extensions.eglStreamConsumerExternal; + mResources.ARB_texture_rectangle = extensions.textureRectangle; // TODO: use shader precision caps to determine if high precision is supported? mResources.FragmentPrecisionHigh = 1; mResources.EXT_frag_depth = extensions.fragDepth; diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp index 2e7ec2981..1c5c6a1b9 100644 --- a/src/libANGLE/Context.cpp +++ b/src/libANGLE/Context.cpp @@ -334,6 +334,13 @@ Context::Context(rx::EGLImplFactory *implFactory, } } + if (mExtensions.textureRectangle) + { + Texture *zeroTextureRectangle = + new Texture(mImplementation.get(), 0, GL_TEXTURE_RECTANGLE_ANGLE); + mZeroTextures[GL_TEXTURE_RECTANGLE_ANGLE].set(this, zeroTextureRectangle); + } + if (mExtensions.eglImageExternal || mExtensions.eglStreamConsumerExternal) { Texture *zeroTextureExternal = @@ -1422,6 +1429,9 @@ void Context::getIntegervImpl(GLenum pname, GLint *params) case GL_MAX_TEXTURE_SIZE: *params = mCaps.max2DTextureSize; break; + case GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE: + *params = mCaps.maxRectangleTextureSize; + break; case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = mCaps.maxCubeMapTextureSize; break; @@ -3028,6 +3038,10 @@ void Context::framebufferTexture2D(GLenum target, { index = ImageIndex::Make2D(level); } + else if (textarget == GL_TEXTURE_RECTANGLE_ANGLE) + { + index = ImageIndex::MakeRectangle(level); + } else if (textarget == GL_TEXTURE_2D_MULTISAMPLE) { ASSERT(level == 0); diff --git a/src/libANGLE/ContextState.cpp b/src/libANGLE/ContextState.cpp index f1e89d9cf..0d240fffc 100644 --- a/src/libANGLE/ContextState.cpp +++ b/src/libANGLE/ContextState.cpp @@ -229,6 +229,17 @@ bool ValidationContext::getQueryParameterInfo(GLenum pname, GLenum *type, unsign *numParams = 1; return true; } + case GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE: + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + { + if (!getExtensions().textureRectangle) + { + return false; + } + *type = GL_INT; + *numParams = 1; + return true; + } case GL_MAX_DRAW_BUFFERS_EXT: case GL_MAX_COLOR_ATTACHMENTS_EXT: { diff --git a/src/libANGLE/ImageIndex.cpp b/src/libANGLE/ImageIndex.cpp index 657e3ade0..e1b662411 100644 --- a/src/libANGLE/ImageIndex.cpp +++ b/src/libANGLE/ImageIndex.cpp @@ -38,6 +38,11 @@ ImageIndex ImageIndex::Make2D(GLint mipIndex) return ImageIndex(GL_TEXTURE_2D, mipIndex, ENTIRE_LEVEL); } +ImageIndex ImageIndex::MakeRectangle(GLint mipIndex) +{ + return ImageIndex(GL_TEXTURE_RECTANGLE_ANGLE, mipIndex, ENTIRE_LEVEL); +} + ImageIndex ImageIndex::MakeCube(GLenum target, GLint mipIndex) { ASSERT(gl::IsCubeMapTextureTarget(target)); @@ -112,6 +117,13 @@ ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) nullptr); } +ImageIndexIterator ImageIndexIterator::MakeRectangle(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_RECTANGLE_ANGLE, Range(minMip, maxMip), + Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), + nullptr); +} + ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) { return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, Range(minMip, maxMip), Range(0, 6), diff --git a/src/libANGLE/ImageIndex.h b/src/libANGLE/ImageIndex.h index 599278445..dff8343b6 100644 --- a/src/libANGLE/ImageIndex.h +++ b/src/libANGLE/ImageIndex.h @@ -31,6 +31,7 @@ struct ImageIndex bool is3D() const; static ImageIndex Make2D(GLint mipIndex); + static ImageIndex MakeRectangle(GLint mipIndex); static ImageIndex MakeCube(GLenum target, GLint mipIndex); static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); @@ -55,6 +56,7 @@ class ImageIndexIterator { public: static ImageIndexIterator Make2D(GLint minMip, GLint maxMip); + static ImageIndexIterator MakeRectangle(GLint minMip, GLint maxMip); static ImageIndexIterator MakeCube(GLint minMip, GLint maxMip); static ImageIndexIterator Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer); static ImageIndexIterator Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts); diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp index 86424cdf9..c771ba06c 100644 --- a/src/libANGLE/State.cpp +++ b/src/libANGLE/State.cpp @@ -150,6 +150,10 @@ void State::initialize(const Context *context, mShaderStorageBuffers.resize(caps.maxShaderStorageBufferBindings); mImageUnits.resize(caps.maxImageUnits); } + if (extensions.textureRectangle) + { + mSamplerTextures[GL_TEXTURE_RECTANGLE_ANGLE].resize(caps.maxCombinedTextureImageUnits); + } if (extensions.eglImageExternal || extensions.eglStreamConsumerExternal) { mSamplerTextures[GL_TEXTURE_EXTERNAL_OES].resize(caps.maxCombinedTextureImageUnits); @@ -1917,6 +1921,11 @@ void State::getIntegerv(const Context *context, GLenum pname, GLint *params) ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = getSamplerTextureId(static_cast(mActiveSampler), GL_TEXTURE_2D); break; + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); + *params = getSamplerTextureId(static_cast(mActiveSampler), + GL_TEXTURE_RECTANGLE_ANGLE); + break; case GL_TEXTURE_BINDING_CUBE_MAP: ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp index 2340e5d96..057d9c6a6 100644 --- a/src/libANGLE/Texture.cpp +++ b/src/libANGLE/Texture.cpp @@ -1158,7 +1158,7 @@ Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *sur mBoundSurface = surface; // Set the image info to the size and format of the surface - ASSERT(mState.mTarget == GL_TEXTURE_2D); + ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE); Extents size(surface->getWidth(), surface->getHeight(), 1); ImageDesc desc(size, Format(surface->getConfig()->renderTargetFormat)); mState.setImageDesc(mState.mTarget, 0, desc); @@ -1173,7 +1173,7 @@ Error Texture::releaseTexImageFromSurface(const Context *context) ANGLE_TRY(mTexture->releaseTexImage(context)); // Erase the image info for level 0 - ASSERT(mState.mTarget == GL_TEXTURE_2D); + ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE); mState.clearImageDesc(mState.mTarget, 0); mDirtyChannel.signal(); return NoError(); diff --git a/src/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp index 4a9a413d9..eccb9b608 100644 --- a/src/libANGLE/renderer/gl/FramebufferGL.cpp +++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp @@ -48,7 +48,8 @@ void BindFramebufferAttachment(const FunctionsGL *functions, const TextureGL *textureGL = GetImplAs(texture); if (texture->getTarget() == GL_TEXTURE_2D || - texture->getTarget() == GL_TEXTURE_2D_MULTISAMPLE) + texture->getTarget() == GL_TEXTURE_2D_MULTISAMPLE || + texture->getTarget() == GL_TEXTURE_RECTANGLE_ANGLE) { functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, texture->getTarget(), textureGL->getTextureID(), diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp index dbaad8bdc..51117bde9 100644 --- a/src/libANGLE/renderer/gl/StateManagerGL.cpp +++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp @@ -171,6 +171,7 @@ StateManagerGL::StateManagerGL(const FunctionsGL *functions, ASSERT(extensions.maxViews >= 1u); mTextures[GL_TEXTURE_2D].resize(rendererCaps.maxCombinedTextureImageUnits); + mTextures[GL_TEXTURE_RECTANGLE_ANGLE].resize(rendererCaps.maxCombinedTextureImageUnits); mTextures[GL_TEXTURE_CUBE_MAP].resize(rendererCaps.maxCombinedTextureImageUnits); mTextures[GL_TEXTURE_2D_ARRAY].resize(rendererCaps.maxCombinedTextureImageUnits); mTextures[GL_TEXTURE_3D].resize(rendererCaps.maxCombinedTextureImageUnits); diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp index 352cc69ec..e45a46250 100644 --- a/src/libANGLE/renderer/gl/TextureGL.cpp +++ b/src/libANGLE/renderer/gl/TextureGL.cpp @@ -41,7 +41,8 @@ size_t GetLevelInfoIndex(GLenum target, size_t level) bool UseTexImage2D(GLenum textureType) { - return textureType == GL_TEXTURE_2D || textureType == GL_TEXTURE_CUBE_MAP; + return textureType == GL_TEXTURE_2D || textureType == GL_TEXTURE_CUBE_MAP || + textureType == GL_TEXTURE_RECTANGLE_ANGLE; } bool UseTexImage3D(GLenum textureType) @@ -811,7 +812,7 @@ gl::Error TextureGL::setStorage(const gl::Context *context, std::max(size.height >> level, 1), 1); - if (getTarget() == GL_TEXTURE_2D) + if (getTarget() == GL_TEXTURE_2D || getTarget() == GL_TEXTURE_RECTANGLE_ANGLE) { if (internalFormatInfo.compressed) { @@ -989,7 +990,7 @@ gl::Error TextureGL::generateMipmap(const gl::Context *context) gl::Error TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface) { - ASSERT(getTarget() == GL_TEXTURE_2D); + ASSERT(getTarget() == GL_TEXTURE_2D || getTarget() == GL_TEXTURE_RECTANGLE_ANGLE); // Make sure this texture is bound mStateManager->bindTexture(getTarget(), mTextureID); @@ -1001,7 +1002,7 @@ gl::Error TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surf gl::Error TextureGL::releaseTexImage(const gl::Context *context) { // Not all Surface implementations reset the size of mip 0 when releasing, do it manually - ASSERT(getTarget() == GL_TEXTURE_2D); + ASSERT(getTarget() == GL_TEXTURE_2D || getTarget() == GL_TEXTURE_RECTANGLE_ANGLE); mStateManager->bindTexture(getTarget(), mTextureID); if (UseTexImage2D(getTarget())) diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp index 92c7f3be4..fb911b9d7 100644 --- a/src/libANGLE/renderer/gl/renderergl_utils.cpp +++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp @@ -1002,6 +1002,14 @@ void GenerateCaps(const FunctionsGL *functions, functions->hasGLESExtension("GL_ARB_invalidate_subdata"); extensions->translatedShaderSource = true; + + if (functions->isAtLeastGL(gl::Version(3, 1)) || + functions->hasGLExtension("GL_ARB_texture_rectangle")) + { + extensions->textureRectangle = true; + caps->maxRectangleTextureSize = + QuerySingleGLInt(functions, GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE); + } } void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds) diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp index 442ed718d..4128289c8 100644 --- a/src/libANGLE/validationEGL.cpp +++ b/src/libANGLE/validationEGL.cpp @@ -35,6 +35,9 @@ size_t GetMaximumMipLevel(const gl::Context *context, GLenum target) case GL_TEXTURE_2D: maxDimension = caps.max2DTextureSize; break; + case GL_TEXTURE_RECTANGLE_ANGLE: + maxDimension = caps.maxRectangleTextureSize; + break; case GL_TEXTURE_CUBE_MAP: maxDimension = caps.maxCubeMapTextureSize; break; diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp index f3ee4938c..cb0b596f2 100644 --- a/src/libANGLE/validationES.cpp +++ b/src/libANGLE/validationES.cpp @@ -257,7 +257,7 @@ bool ValidReadPixelsFormatType(ValidationContext *context, } template -bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isExternalTextureTarget) +bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool restrictedWrapModes) { switch (ConvertToGLenum(params[0])) { @@ -266,11 +266,11 @@ bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isEx case GL_REPEAT: case GL_MIRRORED_REPEAT: - if (isExternalTextureTarget) + if (restrictedWrapModes) { - // OES_EGL_image_external specifies this error. + // OES_EGL_image_external and ANGLE_texture_rectangle specifies this error. context->handleError(InvalidEnum() - << "external textures only support CLAMP_TO_EDGE wrap mode"); + << "texture only support CLAMP_TO_EDGE wrap mode"); return false; } break; @@ -284,9 +284,7 @@ bool ValidateTextureWrapModeValue(Context *context, ParamType *params, bool isEx } template -bool ValidateTextureMinFilterValue(Context *context, - ParamType *params, - bool isExternalTextureTarget) +bool ValidateTextureMinFilterValue(Context *context, ParamType *params, bool restrictedMinFilter) { switch (ConvertToGLenum(params[0])) { @@ -298,11 +296,11 @@ bool ValidateTextureMinFilterValue(Context *context, case GL_LINEAR_MIPMAP_NEAREST: case GL_NEAREST_MIPMAP_LINEAR: case GL_LINEAR_MIPMAP_LINEAR: - if (isExternalTextureTarget) + if (restrictedMinFilter) { // OES_EGL_image_external specifies this error. - context->handleError( - InvalidEnum() << "external textures only support NEAREST and LINEAR filtering"); + context->handleError(InvalidEnum() + << "texture only support NEAREST and LINEAR filtering"); return false; } break; @@ -861,6 +859,9 @@ bool ValidTextureTarget(const ValidationContext *context, GLenum target) case GL_TEXTURE_CUBE_MAP: return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: return (context->getClientMajorVersion() >= 3); @@ -881,6 +882,9 @@ bool ValidTexture2DTarget(const ValidationContext *context, GLenum target) case GL_TEXTURE_CUBE_MAP: return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; + default: return false; } @@ -924,6 +928,8 @@ bool ValidTexture2DDestinationTarget(const ValidationContext *context, GLenum ta case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; default: return false; } @@ -1023,6 +1029,8 @@ bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum tar case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_2D_MULTISAMPLE: return true; + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; default: return false; } @@ -1095,6 +1103,8 @@ bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level) case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: maxDimension = caps.maxCubeMapTextureSize; break; + case GL_TEXTURE_RECTANGLE_ANGLE: + return level == 0; case GL_TEXTURE_3D: maxDimension = caps.max3DTextureSize; break; @@ -2494,6 +2504,14 @@ bool ValidateStateQuery(ValidationContext *context, case GL_TEXTURE_BINDING_2D_ARRAY: case GL_TEXTURE_BINDING_2D_MULTISAMPLE: break; + case GL_TEXTURE_BINDING_RECTANGLE_ANGLE: + if (!context->getExtensions().textureRectangle) + { + context->handleError(InvalidEnum() + << "ANGLE_texture_rectangle extension not present"); + return false; + } + break; case GL_TEXTURE_BINDING_EXTERNAL_OES: if (!context->getExtensions().eglStreamConsumerExternal && !context->getExtensions().eglImageExternal) @@ -2676,6 +2694,10 @@ bool ValidateCopyTexImageParametersBase(ValidationContext *context, maxDimension = caps.maxCubeMapTextureSize; break; + case GL_TEXTURE_RECTANGLE_ANGLE: + maxDimension = caps.maxRectangleTextureSize; + break; + case GL_TEXTURE_2D_ARRAY: maxDimension = caps.max2DTextureSize; break; @@ -5688,16 +5710,24 @@ bool ValidateTexParameterBase(Context *context, case GL_TEXTURE_WRAP_S: case GL_TEXTURE_WRAP_T: case GL_TEXTURE_WRAP_R: - if (!ValidateTextureWrapModeValue(context, params, target == GL_TEXTURE_EXTERNAL_OES)) { - return false; + bool restrictedWrapModes = + target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE; + if (!ValidateTextureWrapModeValue(context, params, restrictedWrapModes)) + { + return false; + } } break; case GL_TEXTURE_MIN_FILTER: - if (!ValidateTextureMinFilterValue(context, params, target == GL_TEXTURE_EXTERNAL_OES)) { - return false; + bool restrictedMinFilter = + target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ANGLE; + if (!ValidateTextureMinFilterValue(context, params, restrictedMinFilter)) + { + return false; + } } break; @@ -5793,6 +5823,12 @@ bool ValidateTexParameterBase(Context *context, << "Base level must be 0 for multisampled textures."); return false; } + if (target == GL_TEXTURE_RECTANGLE_ANGLE && static_cast(params[0]) != 0) + { + context->handleError(InvalidOperation() + << "Base level must be 0 for rectangle textures."); + return false; + } break; case GL_TEXTURE_MAX_LEVEL: diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp index c98e52ac8..2810c1129 100644 --- a/src/libANGLE/validationES2.cpp +++ b/src/libANGLE/validationES2.cpp @@ -314,8 +314,9 @@ bool IsValidCopyTextureDestinationTarget(Context *context, GLenum textureType, G case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return textureType == GL_TEXTURE_CUBE_MAP; - // TODO(geofflang): accept GL_TEXTURE_RECTANGLE_ARB if the texture_rectangle extension is - // supported + case GL_TEXTURE_RECTANGLE_ANGLE: + return textureType == GL_TEXTURE_RECTANGLE_ANGLE && + context->getExtensions().textureRectangle; default: return false; @@ -328,9 +329,8 @@ bool IsValidCopyTextureSourceTarget(Context *context, GLenum target) { case GL_TEXTURE_2D: return true; - - // TODO(geofflang): accept GL_TEXTURE_RECTANGLE_ARB if the texture_rectangle extension is - // supported + case GL_TEXTURE_RECTANGLE_ANGLE: + return context->getExtensions().textureRectangle; // TODO(geofflang): accept GL_TEXTURE_EXTERNAL_OES if the texture_external extension is // supported @@ -375,6 +375,15 @@ bool IsValidCopyTextureDestinationLevel(Context *context, return false; } } + else if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) + { + return false; + } + } else if (IsCubeMapTextureTarget(target)) { if (static_cast(width) > (caps.maxCubeMapTextureSize >> level) || @@ -1002,6 +1011,22 @@ bool ValidateES2TexImageParameters(Context *context, return false; } } + else if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + if (isCompressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + } else if (IsCubeMapTextureTarget(target)) { if (!isSubImage && width != height) @@ -1480,7 +1505,8 @@ bool ValidateES2TexStorageParameters(Context *context, GLsizei width, GLsizei height) { - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) + if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP && + target != GL_TEXTURE_RECTANGLE_ANGLE) { context->handleError(InvalidEnum()); return false; @@ -1523,6 +1549,20 @@ bool ValidateES2TexStorageParameters(Context *context, return false; } break; + case GL_TEXTURE_RECTANGLE_ANGLE: + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize || levels != 1) + { + context->handleError(InvalidValue()); + return false; + } + if (formatInfo.compressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + break; case GL_TEXTURE_CUBE_MAP: if (static_cast(width) > caps.maxCubeMapTextureSize || static_cast(height) > caps.maxCubeMapTextureSize) @@ -2601,6 +2641,12 @@ bool ValidateCompressedTexImage2D(Context *context, return false; } + if (target == GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidEnum() << "Rectangle texture cannot have a compressed format."); + return false; + } + return true; } @@ -2796,6 +2842,15 @@ bool ValidateBindTexture(Context *context, GLenum target, GLuint texture) case GL_TEXTURE_CUBE_MAP: break; + case GL_TEXTURE_RECTANGLE_ANGLE: + if (!context->getExtensions().textureRectangle) + { + context->handleError(InvalidEnum() + << "Context does not support GL_ANGLE_texture_rectangle"); + return false; + } + break; + case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: if (context->getClientMajorVersion() < 3) @@ -5807,6 +5862,22 @@ bool ValidateFramebufferTexture2D(Context *context, } break; + case GL_TEXTURE_RECTANGLE_ANGLE: + { + if (level != 0) + { + context->handleError(InvalidValue()); + return false; + } + if (tex->getTarget() != GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidOperation() + << "Textarget must match the texture target type."); + return false; + } + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: @@ -5954,7 +6025,8 @@ bool ValidateGenerateMipmap(Context *context, GLenum target) (!isPow2(static_cast(texture->getWidth(baseTarget, 0))) || !isPow2(static_cast(texture->getHeight(baseTarget, 0))))) { - ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP); + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ANGLE || + target == GL_TEXTURE_CUBE_MAP); ANGLE_VALIDATION_ERR(context, InvalidOperation(), TextureNotPow2); return false; } diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp index 6cc18273d..3a97b17d4 100644 --- a/src/libANGLE/validationES3.cpp +++ b/src/libANGLE/validationES3.cpp @@ -199,6 +199,22 @@ bool ValidateES3TexImageParametersBase(Context *context, } break; + case GL_TEXTURE_RECTANGLE_ANGLE: + ASSERT(level == 0); + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize) + { + context->handleError(InvalidValue()); + return false; + } + if (isCompressed) + { + context->handleError(InvalidEnum() + << "Rectangle texture cannot have a compressed format."); + return false; + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: @@ -851,6 +867,17 @@ bool ValidateES3TexStorageParametersBase(Context *context, } break; + case GL_TEXTURE_RECTANGLE_ANGLE: + { + if (static_cast(width) > caps.maxRectangleTextureSize || + static_cast(height) > caps.maxRectangleTextureSize || levels != 1) + { + context->handleError(InvalidValue()); + return false; + } + } + break; + case GL_TEXTURE_CUBE_MAP: { if (width != height) @@ -922,6 +949,12 @@ bool ValidateES3TexStorageParametersBase(Context *context, return false; } + if (formatInfo.compressed && target == GL_TEXTURE_RECTANGLE_ANGLE) + { + context->handleError(InvalidEnum() << "Rectangle texture cannot have a compressed format."); + return false; + } + return true; } diff --git a/src/tests/angle_end2end_tests.gypi b/src/tests/angle_end2end_tests.gypi index c7b237332..13b1361e8 100644 --- a/src/tests/angle_end2end_tests.gypi +++ b/src/tests/angle_end2end_tests.gypi @@ -80,6 +80,7 @@ '<(angle_path)/src/tests/gl_tests/SwizzleTest.cpp', '<(angle_path)/src/tests/gl_tests/SyncQueriesTest.cpp', '<(angle_path)/src/tests/gl_tests/TextureMultisampleTest.cpp', + '<(angle_path)/src/tests/gl_tests/TextureRectangleTest.cpp', '<(angle_path)/src/tests/gl_tests/TextureTest.cpp', '<(angle_path)/src/tests/gl_tests/TimerQueriesTest.cpp', '<(angle_path)/src/tests/gl_tests/TransformFeedbackTest.cpp', diff --git a/src/tests/angle_unittests.gypi b/src/tests/angle_unittests.gypi index 99b186744..145d8f947 100644 --- a/src/tests/angle_unittests.gypi +++ b/src/tests/angle_unittests.gypi @@ -49,6 +49,7 @@ '<(angle_path)/src/tests/angle_unittests_utils.h', '<(angle_path)/src/tests/compiler_tests/API_test.cpp', '<(angle_path)/src/tests/compiler_tests/AppendixALimitations_test.cpp', + '<(angle_path)/src/tests/compiler_tests/ARB_texture_rectangle_test.cpp', '<(angle_path)/src/tests/compiler_tests/AtomicCounter_test.cpp', '<(angle_path)/src/tests/compiler_tests/BufferVariables_test.cpp', '<(angle_path)/src/tests/compiler_tests/CollectVariables_test.cpp', diff --git a/src/tests/compiler_tests/ARB_texture_rectangle_test.cpp b/src/tests/compiler_tests/ARB_texture_rectangle_test.cpp new file mode 100644 index 000000000..9b883758f --- /dev/null +++ b/src/tests/compiler_tests/ARB_texture_rectangle_test.cpp @@ -0,0 +1,97 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// ARB_texture_rectangle_test.cpp: +// Test for the ARB_texture_rectangle extension +// + +#include "GLSLANG/ShaderLang.h" +#include "angle_gl.h" +#include "gtest/gtest.h" +#include "tests/test_utils/ShaderCompileTreeTest.h" + +using namespace sh; + +class ARBTextureRectangleTestNoExt : public ShaderCompileTreeTest +{ + protected: + ::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; } + ShShaderSpec getShaderSpec() const override { return SH_GLES3_SPEC; } +}; + +class ARBTextureRectangleTest : public ARBTextureRectangleTestNoExt +{ + protected: + void initResources(ShBuiltInResources *resources) override + { + resources->ARB_texture_rectangle = 1; + } +}; + +// Check that new types and builtins are disallowed if the extension isn't present in the translator +// resources +TEST_F(ARBTextureRectangleTest, NewTypeAndBuiltinsWithoutTranslatorResourceExtension) +{ + // The new builtins require Sampler2DRect so we can't test them independently. + const std::string &shaderString = + "precision mediump float;\n" + "uniform sampler2DRect tex;\n" + "void main() {\n" + "}\n"; + ASSERT_TRUE(compile(shaderString)); +} + +// Check that new types and builtins are usable even with the #extension directive +// Issue #15 of ARB_texture_rectangle explains that the extension was specified before the +// #extension mechanism was in place so it doesn't require explicit enabling. +TEST_F(ARBTextureRectangleTest, NewTypeAndBuiltinsWithoutExtensionDirective) +{ + const std::string &shaderString = + "precision mediump float;\n" + "uniform sampler2DRect tex;\n" + "void main() {\n" + " vec4 color = texture2DRect(tex, vec2(1.0));" + " color = texture2DRectProj(tex, vec3(1.0));" + " color = texture2DRectProj(tex, vec4(1.0));" + "}\n"; + ASSERT_TRUE(compile(shaderString)); +} + +// Test valid usage of the new types and builtins +TEST_F(ARBTextureRectangleTest, NewTypeAndBuiltingsWithExtensionDirective) +{ + const std::string &shaderString = + "#extension GL_ARB_texture_rectangle : require\n" + "precision mediump float;\n" + "uniform sampler2DRect tex;\n" + "void main() {\n" + " vec4 color = texture2DRect(tex, vec2(1.0));" + " color = texture2DRectProj(tex, vec3(1.0));" + " color = texture2DRectProj(tex, vec4(1.0));" + "}\n"; + ASSERT_TRUE(compile(shaderString)); +} + +// Check that it is not possible to pass a sampler2DRect where sampler2D is expected, and vice versa +TEST_F(ARBTextureRectangleTest, Rect2DVs2DMismatch) +{ + const std::string &shaderString1 = + "#extension GL_ARB_texture_rectangle : require\n" + "precision mediump float;\n" + "uniform sampler2DRect tex;\n" + "void main() {\n" + " vec4 color = texture2D(tex, vec2(1.0));" + "}\n"; + ASSERT_FALSE(compile(shaderString1)); + + const std::string &shaderString2 = + "#extension GL_ARB_texture_rectangle : require\n" + "precision mediump float;\n" + "uniform sampler2D tex;\n" + "void main() {\n" + " vec4 color = texture2DRect(tex, vec2(1.0));" + "}\n"; + ASSERT_FALSE(compile(shaderString2)); +} diff --git a/src/tests/compiler_tests/VariablePacker_test.cpp b/src/tests/compiler_tests/VariablePacker_test.cpp index dd9b0b5b6..bdbc379f5 100644 --- a/src/tests/compiler_tests/VariablePacker_test.cpp +++ b/src/tests/compiler_tests/VariablePacker_test.cpp @@ -10,48 +10,48 @@ #include "compiler/translator/VariablePacker.h" static sh::GLenum types[] = { - GL_FLOAT_MAT4, // 0 - GL_FLOAT_MAT2, // 1 - GL_FLOAT_VEC4, // 2 - GL_INT_VEC4, // 3 - GL_BOOL_VEC4, // 4 - GL_FLOAT_MAT3, // 5 - GL_FLOAT_VEC3, // 6 - GL_INT_VEC3, // 7 - GL_BOOL_VEC3, // 8 - GL_FLOAT_VEC2, // 9 - GL_INT_VEC2, // 10 - GL_BOOL_VEC2, // 11 - GL_FLOAT, // 12 - GL_INT, // 13 - GL_BOOL, // 14 - GL_SAMPLER_2D, // 15 - GL_SAMPLER_CUBE, // 16 - GL_SAMPLER_EXTERNAL_OES, // 17 - GL_SAMPLER_2D_RECT_ARB, // 18 - GL_UNSIGNED_INT, // 19 - GL_UNSIGNED_INT_VEC2, // 20 - GL_UNSIGNED_INT_VEC3, // 21 - GL_UNSIGNED_INT_VEC4, // 22 - GL_FLOAT_MAT2x3, // 23 - GL_FLOAT_MAT2x4, // 24 - GL_FLOAT_MAT3x2, // 25 - GL_FLOAT_MAT3x4, // 26 - GL_FLOAT_MAT4x2, // 27 - GL_FLOAT_MAT4x3, // 28 - GL_SAMPLER_3D, // 29 - GL_SAMPLER_2D_ARRAY, // 30 - GL_SAMPLER_2D_SHADOW, // 31 - GL_SAMPLER_CUBE_SHADOW, // 32 - GL_SAMPLER_2D_ARRAY_SHADOW, // 33 - GL_INT_SAMPLER_2D, // 34 - GL_INT_SAMPLER_CUBE, // 35 - GL_INT_SAMPLER_3D, // 36 - GL_INT_SAMPLER_2D_ARRAY, // 37 - GL_UNSIGNED_INT_SAMPLER_2D, // 38 - GL_UNSIGNED_INT_SAMPLER_CUBE, // 39 - GL_UNSIGNED_INT_SAMPLER_3D, // 40 - GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, // 41 + GL_FLOAT_MAT4, // 0 + GL_FLOAT_MAT2, // 1 + GL_FLOAT_VEC4, // 2 + GL_INT_VEC4, // 3 + GL_BOOL_VEC4, // 4 + GL_FLOAT_MAT3, // 5 + GL_FLOAT_VEC3, // 6 + GL_INT_VEC3, // 7 + GL_BOOL_VEC3, // 8 + GL_FLOAT_VEC2, // 9 + GL_INT_VEC2, // 10 + GL_BOOL_VEC2, // 11 + GL_FLOAT, // 12 + GL_INT, // 13 + GL_BOOL, // 14 + GL_SAMPLER_2D, // 15 + GL_SAMPLER_CUBE, // 16 + GL_SAMPLER_EXTERNAL_OES, // 17 + GL_SAMPLER_2D_RECT_ANGLE, // 18 + GL_UNSIGNED_INT, // 19 + GL_UNSIGNED_INT_VEC2, // 20 + GL_UNSIGNED_INT_VEC3, // 21 + GL_UNSIGNED_INT_VEC4, // 22 + GL_FLOAT_MAT2x3, // 23 + GL_FLOAT_MAT2x4, // 24 + GL_FLOAT_MAT3x2, // 25 + GL_FLOAT_MAT3x4, // 26 + GL_FLOAT_MAT4x2, // 27 + GL_FLOAT_MAT4x3, // 28 + GL_SAMPLER_3D, // 29 + GL_SAMPLER_2D_ARRAY, // 30 + GL_SAMPLER_2D_SHADOW, // 31 + GL_SAMPLER_CUBE_SHADOW, // 32 + GL_SAMPLER_2D_ARRAY_SHADOW, // 33 + GL_INT_SAMPLER_2D, // 34 + GL_INT_SAMPLER_CUBE, // 35 + GL_INT_SAMPLER_3D, // 36 + GL_INT_SAMPLER_2D_ARRAY, // 37 + GL_UNSIGNED_INT_SAMPLER_2D, // 38 + GL_UNSIGNED_INT_SAMPLER_CUBE, // 39 + GL_UNSIGNED_INT_SAMPLER_3D, // 40 + GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, // 41 }; static sh::GLenum nonSqMatTypes[] = { diff --git a/src/tests/gl_tests/TextureRectangleTest.cpp b/src/tests/gl_tests/TextureRectangleTest.cpp new file mode 100644 index 000000000..7da0161c3 --- /dev/null +++ b/src/tests/gl_tests/TextureRectangleTest.cpp @@ -0,0 +1,398 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// TextureRectangleTest: Tests of GL_ANGLE_texture_rectangle + +#include "test_utils/ANGLETest.h" +#include "test_utils/gl_raii.h" + +using namespace angle; + +namespace +{ + +class TextureRectangleTest : public ANGLETest +{ + protected: + TextureRectangleTest() + { + setWindowWidth(64); + setWindowHeight(64); + setConfigRedBits(8); + setConfigGreenBits(8); + setConfigBlueBits(8); + setConfigAlphaBits(8); + } + + bool checkExtensionSupported() const + { + if (!extensionEnabled("GL_ANGLE_texture_rectangle")) + { + std::cout << "Test skipped because GL_ANGLE_texture_rectangle is not available." + << std::endl; + return false; + } + return true; + } +}; + +class TextureRectangleTestES3 : public TextureRectangleTest +{ +}; + +class TextureRectangleTestES31 : public TextureRectangleTest +{ +}; + +// Test using TexImage2D to define a rectangle texture +TEST_P(TextureRectangleTest, TexImage2D) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + + // Defining level 0 is allowed + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + ASSERT_GL_NO_ERROR(); + + // Defining level other than 0 is not allowed + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + ASSERT_GL_ERROR(GL_INVALID_VALUE); + + GLint maxSize = 0; + glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE, &maxSize); + + // Defining a texture of the max size is allowed + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, maxSize, maxSize, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + ASSERT_GL_NO_ERROR(); + + // Defining a texture of the max size is allowed + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, maxSize + 1, maxSize, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + ASSERT_GL_ERROR(GL_INVALID_VALUE); + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, maxSize, maxSize + 1, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + ASSERT_GL_ERROR(GL_INVALID_VALUE); +} + +// Test using CompressedTexImage2D cannot be used on a retangle texture +TEST_P(TextureRectangleTest, CompressedTexImage2DDisallowed) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_texture_compression_dxt1")); + + const char data[128] = {0}; + + // Control case: 2D texture + { + GLTexture tex; + glBindTexture(GL_TEXTURE_2D, tex); + glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 16, 16, 0, 128, + data); + ASSERT_GL_NO_ERROR(); + } + + // Rectangle textures cannot be compressed + { + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + glCompressedTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 16, + 16, 0, 128, data); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + } +} + +// Test using TexStorage2D to define a rectangle texture +TEST_P(TextureRectangleTest, TexStorage2D) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 && !extensionEnabled("GL_EXT_texture_storage")); + + bool useES3 = getClientMajorVersion() >= 3; + auto TexStorage2D = [useES3](GLenum target, GLint levels, GLenum format, GLint width, + GLint height) { + if (useES3) + { + glTexStorage2D(target, levels, format, width, height); + } + else + { + glTexStorage2DEXT(target, levels, format, width, height); + } + }; + + // Defining one level is allowed + { + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + TexStorage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_RGBA8UI, 16, 16); + ASSERT_GL_NO_ERROR(); + } + + // Having more than one level is not allowed + { + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + // Use 5 levels because the EXT_texture_storage extension requires a mip chain all the way + // to a 1x1 mip. + TexStorage2D(GL_TEXTURE_RECTANGLE_ANGLE, 5, GL_RGBA8UI, 16, 16); + ASSERT_GL_ERROR(GL_INVALID_VALUE); + } + + GLint maxSize = 0; + glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE, &maxSize); + + // Defining a texture of the max size is allowed + { + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + TexStorage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_RGBA8UI, maxSize, maxSize); + ASSERT_GL_NO_ERROR(); + } + + // Defining a texture of the max size is allowed + { + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + TexStorage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_RGBA8UI, maxSize + 1, maxSize); + ASSERT_GL_ERROR(GL_INVALID_VALUE); + TexStorage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_RGBA8UI, maxSize, maxSize + 1); + ASSERT_GL_ERROR(GL_INVALID_VALUE); + } + + // Compressed formats are disallowed + if (extensionEnabled("GL_EXT_texture_compression_dxt1")) + { + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + TexStorage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 16, 16); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + } +} + +// Test validation of disallowed texture parameters +TEST_P(TextureRectangleTest, TexParameterRestriction) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + + // Only wrap mode CLAMP_TO_EDGE is supported + // Wrap S + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + ASSERT_GL_NO_ERROR(); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_S, GL_REPEAT); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + + // Wrap T + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + ASSERT_GL_NO_ERROR(); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_T, GL_REPEAT); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + + // Min filter has to be nearest or linear + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + ASSERT_GL_NO_ERROR(); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ASSERT_GL_NO_ERROR(); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + ASSERT_GL_ERROR(GL_INVALID_ENUM); + + // Base level has to be 0 + if (getClientMajorVersion() >= 3) + { + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_BASE_LEVEL, 0); + ASSERT_GL_NO_ERROR(); + glTexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_BASE_LEVEL, 1); + ASSERT_GL_ERROR(GL_INVALID_OPERATION); + } +} + +// Test validation of 'level' in GetTexParameter +TEST_P(TextureRectangleTestES31, GetTexLevelParameter) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + ASSERT_GL_NO_ERROR(); + + GLint param; + // Control case: level 0 is ok. + glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, ¶m); + ASSERT_GL_NO_ERROR(); + + // Level 1 is not ok. + glGetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_TEXTURE_INTERNAL_FORMAT, ¶m); + ASSERT_GL_ERROR(GL_INVALID_VALUE); +} + +// Test validation of "level" in FramebufferTexture2D +TEST_P(TextureRectangleTest, FramebufferTexture2DLevel) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + ASSERT_GL_NO_ERROR(); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + // Using level 0 of a rectangle texture is valid. + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, + 0); + EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); + ASSERT_GL_NO_ERROR(); + + // Setting level != 0 is invalid + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, + 1); + ASSERT_GL_ERROR(GL_INVALID_VALUE); +} + +// Test sampling from a rectangle texture +TEST_P(TextureRectangleTest, SamplingFromRectangle) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, + &GLColor::green); + + const std::string vs = + "attribute vec4 position;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(position.xy, 0.0, 1.0);\n" + "}\n"; + + const std::string fs = + "#extension GL_ARB_texture_rectangle : require\n" + "precision mediump float;\n" + "uniform sampler2DRect tex;\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2DRect(tex, vec2(0, 0));\n" + "}\n"; + + ANGLE_GL_PROGRAM(program, vs, fs); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + drawQuad(program, "position", 0.5f, 1.0f, false); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + ASSERT_GL_NO_ERROR(); +} + +// Test attaching a rectangle texture and rendering to it. +TEST_P(TextureRectangleTest, RenderToRectangle) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, + &GLColor::black); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, + 0); + EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER)); + ASSERT_GL_NO_ERROR(); + + // Clearing a texture is just as good as checking we can render to it, right? + glClearColor(0.0, 1.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + ASSERT_GL_NO_ERROR(); +} + +// Test glCopyTexImage with rectangle textures +TEST_P(TextureRectangleTestES3, CopyTexImage) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClearColor(0, 1, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + ASSERT_GL_NO_ERROR(); + + // Error case: level != 0 + glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, GL_RGBA8, 0, 0, 1, 1, 0); + ASSERT_GL_ERROR(GL_INVALID_VALUE); + + // level = 0 works and defines the texture. + glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA8, 0, 0, 1, 1, 0); + ASSERT_GL_NO_ERROR(); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, + 0); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + ASSERT_GL_NO_ERROR(); +} + +// Test glCopyTexSubImage with rectangle textures +TEST_P(TextureRectangleTestES3, CopyTexSubImage) +{ + ANGLE_SKIP_TEST_IF(!checkExtensionSupported()); + + GLTexture tex; + glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex); + glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, + &GLColor::black); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClearColor(0, 1, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + ASSERT_GL_NO_ERROR(); + + // Error case: level != 0 + glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 1, 0, 0, 0, 0, 1, 1); + ASSERT_GL_ERROR(GL_INVALID_VALUE); + + // level = 0 works and defines the texture. + glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, 0, 0, 0, 0, 1, 1); + ASSERT_GL_NO_ERROR(); + + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, + 0); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + ASSERT_GL_NO_ERROR(); +} + +ANGLE_INSTANTIATE_TEST(TextureRectangleTest, ES2_OPENGL(), ES3_OPENGL()); +ANGLE_INSTANTIATE_TEST(TextureRectangleTestES3, ES3_OPENGL()); +ANGLE_INSTANTIATE_TEST(TextureRectangleTestES31, ES31_OPENGL()); +} // anonymous namespace