diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h index 91201540c..4bc006c05 100644 --- a/include/GLSLANG/ShaderLang.h +++ b/include/GLSLANG/ShaderLang.h @@ -48,7 +48,7 @@ typedef unsigned int GLenum; // Version number for shader translation API. // It is incremented every time the API changes. -#define ANGLE_SH_VERSION 145 +#define ANGLE_SH_VERSION 146 typedef enum { SH_GLES2_SPEC = 0x8B40, @@ -255,6 +255,7 @@ typedef struct // Set to 1 to enable the extension, else 0. int OES_standard_derivatives; int OES_EGL_image_external; + int OES_EGL_image_external_essl3; int NV_EGL_stream_consumer_external; int ARB_texture_rectangle; int EXT_blend_func_extended; diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp index 66da0c2d6..93062ca6a 100644 --- a/src/compiler/translator/Compiler.cpp +++ b/src/compiler/translator/Compiler.cpp @@ -480,6 +480,8 @@ void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType) void TCompiler::setResourceString() { std::ostringstream strstream; + + // clang-format off strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors @@ -490,6 +492,8 @@ void TCompiler::setResourceString() << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external + << ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3 + << ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh @@ -509,6 +513,7 @@ void TCompiler::setResourceString() << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers << ":NV_draw_buffers:" << compileResources.NV_draw_buffers << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision; + // clang-format on builtInResourcesString = strstream.str(); } diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp index ff35d2069..a50c017f0 100644 --- a/src/compiler/translator/Initialize.cpp +++ b/src/compiler/translator/Initialize.cpp @@ -315,6 +315,17 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsamplerCube, float3, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureLod", gsampler2DArray, float3, float1); + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float3); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float4); + } + if (type == GL_FRAGMENT_SHADER) { symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texture", gsampler2D, float2, float1); @@ -324,6 +335,18 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float3, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler2D, float4, float1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "textureProj", gsampler3D, float4, float1); + + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2, + float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float3, float1); + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES, + float4, float1); + } } const TType *sampler2DShadow = TCache::getType(EbtSampler2DShadow); @@ -351,6 +374,13 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerCubeShadow, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, int3, "textureSize", sampler2DArrayShadow, int1); + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerExternalOES, int1); + } + if (type == GL_FRAGMENT_SHADER) { symbolTable.insertBuiltIn(ESSL3_BUILTINS, EOpDFdx, genType, "dFdx", genType); @@ -403,6 +433,14 @@ void InsertBuiltInFunctions(sh::GLenum type, ShShaderSpec spec, const ShBuiltInR symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler3D, int3, int1); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetch", gsampler2DArray, int3, int1); + if (resources.OES_EGL_image_external_essl3) + { + const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES); + + symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texelFetch", samplerExternalOES, int2, + int1); + } + symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2D, int2, int1, int2); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler3D, int3, int1, int3); symbolTable.insertBuiltIn(ESSL3_BUILTINS, gvec4, "texelFetchOffset", gsampler2DArray, int3, int1, int2); @@ -594,6 +632,8 @@ void InitExtensionBehavior(const ShBuiltInResources& resources, extBehavior["GL_OES_standard_derivatives"] = EBhUndefined; if (resources.OES_EGL_image_external) extBehavior["GL_OES_EGL_image_external"] = EBhUndefined; + if (resources.OES_EGL_image_external_essl3) + extBehavior["GL_OES_EGL_image_external_essl3"] = EBhUndefined; if (resources.NV_EGL_stream_consumer_external) extBehavior["GL_NV_EGL_stream_consumer_external"] = EBhUndefined; if (resources.ARB_texture_rectangle) diff --git a/src/compiler/translator/ShaderLang.cpp b/src/compiler/translator/ShaderLang.cpp index 421597b9b..e4f27fb1b 100644 --- a/src/compiler/translator/ShaderLang.cpp +++ b/src/compiler/translator/ShaderLang.cpp @@ -148,6 +148,8 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) // Extensions. resources->OES_standard_derivatives = 0; resources->OES_EGL_image_external = 0; + resources->OES_EGL_image_external_essl3 = 0; + resources->NV_EGL_stream_consumer_external = 0; resources->ARB_texture_rectangle = 0; resources->EXT_blend_func_extended = 0; resources->EXT_draw_buffers = 0; diff --git a/src/compiler/translator/TextureFunctionHLSL.cpp b/src/compiler/translator/TextureFunctionHLSL.cpp index b859310ac..f0b48d047 100644 --- a/src/compiler/translator/TextureFunctionHLSL.cpp +++ b/src/compiler/translator/TextureFunctionHLSL.cpp @@ -201,6 +201,7 @@ int GetHLSLCoordCount(const TextureFunctionHLSL::TextureFunction &textureFunctio switch (textureFunction.sampler) { case EbtSampler2D: + case EbtSamplerExternalOES: hlslCoords = 2; break; case EbtSamplerCube: @@ -275,6 +276,7 @@ void OutputTextureFunctionArgumentList(TInfoSinkBase &out, switch (textureFunction.sampler) { case EbtSampler2D: + case EbtSamplerExternalOES: out << "sampler2D s"; break; case EbtSamplerCube: @@ -790,6 +792,7 @@ void OutputTextureSampleFunctionReturnStatement( switch (textureFunction.sampler) { case EbtSampler2D: + case EbtSamplerExternalOES: out << "tex2D"; break; case EbtSamplerCube: diff --git a/src/libANGLE/Compiler.cpp b/src/libANGLE/Compiler.cpp index 15e094ea3..127ecd818 100644 --- a/src/libANGLE/Compiler.cpp +++ b/src/libANGLE/Compiler.cpp @@ -50,8 +50,8 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &data) mResources.OES_standard_derivatives = extensions.standardDerivatives; mResources.EXT_draw_buffers = extensions.drawBuffers; mResources.EXT_shader_texture_lod = extensions.shaderTextureLOD; - // TODO: disabled until the extension is actually supported. - mResources.OES_EGL_image_external = 0; + mResources.OES_EGL_image_external = extensions.eglImageExternal; + mResources.OES_EGL_image_external_essl3 = extensions.eglImageExternalEssl3; mResources.NV_EGL_stream_consumer_external = extensions.eglStreamConsumerExternal; // TODO: use shader precision caps to determine if high precision is supported? mResources.FragmentPrecisionHigh = 1; diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp index ca43a1090..19fd7117b 100644 --- a/src/libANGLE/Context.cpp +++ b/src/libANGLE/Context.cpp @@ -2089,6 +2089,7 @@ void Context::initCaps(GLuint clientVersion) { // Disable ES3+ extensions mExtensions.colorBufferFloat = false; + mExtensions.eglImageExternalEssl3 = false; } if (clientVersion > 2) diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp index 7b8aef809..79cb69399 100644 --- a/src/libANGLE/Texture.cpp +++ b/src/libANGLE/Texture.cpp @@ -61,7 +61,7 @@ TextureState::TextureState(GLenum target) swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA), - samplerState(), + samplerState(SamplerState::CreateDefaultForTarget(target)), baseLevel(0), maxLevel(1000), immutableFormat(false), @@ -755,7 +755,7 @@ void Texture::releaseTexImageInternal() Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget) { ASSERT(target == mState.target); - ASSERT(target == GL_TEXTURE_2D); + ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES); // Release from previous calls to eglBindTexImage, to avoid calling the Impl after releaseTexImageInternal(); @@ -847,6 +847,27 @@ bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, } } + // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a + // texture unit that would have been rejected by a call to TexParameter* for the texture bound + // to that unit, the behavior of the implementation is as if the texture were incomplete. For + // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the + // sampler object bound to a texture unit and the texture bound to that unit is an external + // texture, the texture will be considered incomplete. + // Sampler object state which does not affect sampling for the type of texture bound to a + // texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness. + if (mState.target == GL_TEXTURE_EXTERNAL_OES) + { + if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE) + { + return false; + } + + if (samplerState.minFilter != GL_LINEAR && samplerState.minFilter != GL_NEAREST) + { + return false; + } + } + // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if: // The internalformat specified for the texture arrays is a sized internal depth or // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_- diff --git a/src/libANGLE/angletypes.cpp b/src/libANGLE/angletypes.cpp index 3a636c9e4..0cd69963e 100644 --- a/src/libANGLE/angletypes.cpp +++ b/src/libANGLE/angletypes.cpp @@ -53,6 +53,23 @@ SamplerState::SamplerState() { } +// static +SamplerState SamplerState::CreateDefaultForTarget(GLenum target) +{ + SamplerState state; + + // According to OES_EGL_image_external: For external textures, the default min filter is + // GL_LINEAR and the default s and t wrap modes are GL_CLAMP_TO_EDGE. + if (target == GL_TEXTURE_EXTERNAL_OES) + { + state.minFilter = GL_LINEAR; + state.wrapS = GL_CLAMP_TO_EDGE; + state.wrapT = GL_CLAMP_TO_EDGE; + } + + return state; +} + static void MinMax(int a, int b, int *minimum, int *maximum) { if (a < b) diff --git a/src/libANGLE/angletypes.h b/src/libANGLE/angletypes.h index 0cd533ebe..52c4b6214 100644 --- a/src/libANGLE/angletypes.h +++ b/src/libANGLE/angletypes.h @@ -194,6 +194,7 @@ struct DepthStencilState struct SamplerState { SamplerState(); + static SamplerState CreateDefaultForTarget(GLenum target); GLenum minFilter; GLenum magFilter; diff --git a/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/libANGLE/renderer/d3d/TextureD3D.cpp index 728bc9b8e..fb63c2e3b 100644 --- a/src/libANGLE/renderer/d3d/TextureD3D.cpp +++ b/src/libANGLE/renderer/d3d/TextureD3D.cpp @@ -3178,21 +3178,17 @@ void TextureD3D_2DArray::markAllImagesDirty() TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer) : TextureD3D(state, renderer) { - mImage = renderer->createImage(); } TextureD3D_External::~TextureD3D_External() { - SafeDelete(mImage); SafeDelete(mTexStorage); } ImageD3D *TextureD3D_External::getImage(const gl::ImageIndex &index) const { - // External images only have one mipmap level - ASSERT(index.type == GL_TEXTURE_EXTERNAL_OES); - ASSERT(index.mipIndex == 0); - return mImage; + UNREACHABLE(); + return nullptr; } GLsizei TextureD3D_External::getLayerCount(int level) const @@ -3200,29 +3196,6 @@ GLsizei TextureD3D_External::getLayerCount(int level) const return 1; } -GLsizei TextureD3D_External::getWidth(GLint level) const -{ - ASSERT(level == 0); - return mImage->getWidth(); -} - -GLsizei TextureD3D_External::getHeight(GLint level) const -{ - ASSERT(level == 0); - return mImage->getHeight(); -} - -GLenum TextureD3D_External::getInternalFormat(GLint level) const -{ - ASSERT(level == 0); - return mImage->getInternalFormat(); -} - -bool TextureD3D_External::isDepth(GLint level) const -{ - return false; -} - gl::Error TextureD3D_External::setImage(GLenum target, size_t imageLevel, GLenum internalFormat, @@ -3308,15 +3281,11 @@ gl::Error TextureD3D_External::setImageExternal(GLenum target, { ASSERT(target == GL_TEXTURE_EXTERNAL_OES); - // If the strean is null, the external image is unbound and we release the storage - if (stream == nullptr) + SafeDelete(mTexStorage); + + // If the stream is null, the external image is unbound and we release the storage + if (stream != nullptr) { - SafeDelete(mTexStorage); - mTexStorage = nullptr; - } - else - { - SafeDelete(mTexStorage); mTexStorage = mRenderer->createTextureStorageExternal(stream, desc); } @@ -3335,8 +3304,12 @@ void TextureD3D_External::releaseTexImage() gl::Error TextureD3D_External::setEGLImageTarget(GLenum target, egl::Image *image) { - UNREACHABLE(); - return gl::Error(GL_INVALID_OPERATION); + EGLImageD3D *eglImaged3d = GetImplAs(image); + + SafeDelete(mTexStorage); + mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d); + + return gl::NoError(); } void TextureD3D_External::initMipmapsImages() @@ -3350,19 +3323,9 @@ gl::Error TextureD3D_External::getRenderTarget(const gl::ImageIndex &index, Rend return gl::Error(GL_INVALID_OPERATION); } -bool TextureD3D_External::isValidLevel(int level) const -{ - return (level == 0); -} - -bool TextureD3D_External::isLevelComplete(int level) const -{ - return (level == 0) ? (mTexStorage != nullptr) : false; -} - bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const { - return isLevelComplete(index.mipIndex); + return (index.mipIndex == 0) ? (mTexStorage != nullptr) : false; } gl::Error TextureD3D_External::initializeStorage(bool renderTarget) @@ -3393,20 +3356,6 @@ gl::Error TextureD3D_External::updateStorage() return gl::Error(GL_NO_ERROR); } -gl::Error TextureD3D_External::updateStorageLevel(int level) -{ - UNREACHABLE(); - return gl::Error(GL_NO_ERROR); -} - -void TextureD3D_External::redefineImage(size_t level, - GLenum internalformat, - const gl::Extents &size, - bool forceRelease) -{ - UNREACHABLE(); -} - gl::ImageIndexIterator TextureD3D_External::imageIterator() const { return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); diff --git a/src/libANGLE/renderer/d3d/TextureD3D.h b/src/libANGLE/renderer/d3d/TextureD3D.h index 412d738e9..eedb9f6a6 100644 --- a/src/libANGLE/renderer/d3d/TextureD3D.h +++ b/src/libANGLE/renderer/d3d/TextureD3D.h @@ -413,11 +413,6 @@ class TextureD3D_External : public TextureD3D ImageD3D *getImage(const gl::ImageIndex &index) const override; GLsizei getLayerCount(int level) const override; - GLsizei getWidth(GLint level) const; - GLsizei getHeight(GLint level) const; - GLenum getInternalFormat(GLint level) const; - bool isDepth(GLint level) const; - gl::Error setImage(GLenum target, size_t level, GLenum internalFormat, @@ -492,18 +487,7 @@ class TextureD3D_External : public TextureD3D gl::Error updateStorage() override; void initMipmapsImages() override; - bool isValidLevel(int level) const; - bool isLevelComplete(int level) const; bool isImageComplete(const gl::ImageIndex &index) const override; - - gl::Error updateStorageLevel(int level); - - void redefineImage(size_t level, - GLenum internalformat, - const gl::Extents &size, - bool forceRelease); - - ImageD3D *mImage; }; } diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp index a26152e68..7da9be403 100644 --- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp @@ -1231,6 +1231,8 @@ void GenerateCaps(ID3D11Device *device, ID3D11DeviceContext *deviceContext, cons extensions->fboRenderMipmap = false; extensions->debugMarker = true; extensions->eglImage = true; + extensions->eglImageExternal = true; + extensions->eglImageExternalEssl3 = true; extensions->eglStreamConsumerExternal = true; extensions->unpackSubimage = true; extensions->packSubimage = true; diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp index a1e30d12a..6949d01f1 100644 --- a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp +++ b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp @@ -69,6 +69,8 @@ TextureImpl *Context9::createTexture(const gl::TextureState &state) return new TextureD3D_2D(state, mRenderer); case GL_TEXTURE_CUBE_MAP: return new TextureD3D_Cube(state, mRenderer); + case GL_TEXTURE_EXTERNAL_OES: + return new TextureD3D_External(state, mRenderer); default: UNREACHABLE(); } diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp index 329535936..dd578a119 100644 --- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp @@ -1657,6 +1657,7 @@ gl::Error Renderer9::applyUniforms(const ProgramD3D &programD3D, { case GL_SAMPLER_2D: case GL_SAMPLER_CUBE: + case GL_SAMPLER_EXTERNAL_OES: break; case GL_BOOL: case GL_BOOL_VEC2: diff --git a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp index b55f7dcfe..2c0629516 100644 --- a/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp +++ b/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp @@ -590,6 +590,7 @@ void GenerateCaps(IDirect3D9 *d3d9, extensions->colorBufferFloat = false; extensions->debugMarker = true; extensions->eglImage = true; + extensions->eglImageExternal = true; extensions->unpackSubimage = true; extensions->packSubimage = true; extensions->vertexArrayObject = true; diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp index 76e8c64fe..30c7b5474 100644 --- a/src/libANGLE/validationES.cpp +++ b/src/libANGLE/validationES.cpp @@ -857,13 +857,18 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pnam case GL_TEXTURE_COMPARE_FUNC: case GL_TEXTURE_MIN_LOD: case GL_TEXTURE_MAX_LOD: - // ES3 texture paramters are not supported on external textures as the extension is - // written against ES2. - if (context->getClientVersion() < 3 || target == GL_TEXTURE_EXTERNAL_OES) + if (context->getClientVersion() < 3) { context->handleError(Error(GL_INVALID_ENUM)); return false; } + if (target == GL_TEXTURE_EXTERNAL_OES && !context->getExtensions().eglImageExternalEssl3) + { + context->handleError(Error(GL_INVALID_ENUM, + "ES3 texture parameters are not available without " + "GL_OES_EGL_image_external_essl3.")); + return false; + } break; default: break; @@ -1014,16 +1019,20 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum target, GLenum pnam break; case GL_TEXTURE_BASE_LEVEL: - case GL_TEXTURE_MAX_LEVEL: - if (target == GL_TEXTURE_EXTERNAL_OES) + if (param < 0) { - // This is not specified, but in line with the spirit of OES_EGL_image_external spec, - // which generally forbids setting mipmap related parameters on external textures. - context->handleError( - Error(GL_INVALID_OPERATION, - "Setting the base level or max level of external textures not supported")); + context->handleError(Error(GL_INVALID_VALUE)); return false; } + if (target == GL_TEXTURE_EXTERNAL_OES && param != 0) + { + context->handleError( + Error(GL_INVALID_OPERATION, "Base level must be 0 for external textures.")); + return false; + } + return true; + + case GL_TEXTURE_MAX_LEVEL: if (param < 0) { context->handleError(Error(GL_INVALID_VALUE)); @@ -2398,6 +2407,20 @@ bool ValidateEGLImageTargetTexture2DOES(Context *context, switch (target) { case GL_TEXTURE_2D: + if (!context->getExtensions().eglImage) + { + context->handleError(Error( + GL_INVALID_ENUM, "GL_TEXTURE_2D texture target requires GL_OES_EGL_image.")); + } + break; + + case GL_TEXTURE_EXTERNAL_OES: + if (!context->getExtensions().eglImageExternal) + { + context->handleError(Error( + GL_INVALID_ENUM, + "GL_TEXTURE_EXTERNAL_OES texture target requires GL_OES_EGL_image_external.")); + } break; default: diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp index 6e3810018..309f223e9 100644 --- a/src/libANGLE/validationES2.cpp +++ b/src/libANGLE/validationES2.cpp @@ -1997,7 +1997,8 @@ bool ValidateBindTexture(Context *context, GLenum target, GLuint texture) } break; case GL_TEXTURE_EXTERNAL_OES: - if (!context->getExtensions().eglStreamConsumerExternal) + if (!context->getExtensions().eglImageExternal && + !context->getExtensions().eglStreamConsumerExternal) { context->handleError( Error(GL_INVALID_ENUM, "External texture extension not enabled")); diff --git a/src/libGLESv2/entry_points_gles_2_0.cpp b/src/libGLESv2/entry_points_gles_2_0.cpp index 2babb5617..f23f4988d 100644 --- a/src/libGLESv2/entry_points_gles_2_0.cpp +++ b/src/libGLESv2/entry_points_gles_2_0.cpp @@ -2279,7 +2279,7 @@ void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidTextureTarget(context, target)) + if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) { context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target")); return; @@ -2434,7 +2434,7 @@ void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params) Context *context = GetValidGlobalContext(); if (context) { - if (!ValidTextureTarget(context, target)) + if (!ValidTextureTarget(context, target) && !ValidTextureExternalTarget(context, target)) { context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target")); return; diff --git a/src/tests/egl_tests/EGLStreamTest.cpp b/src/tests/egl_tests/EGLStreamTest.cpp index 020d902f2..1453a640b 100644 --- a/src/tests/egl_tests/EGLStreamTest.cpp +++ b/src/tests/egl_tests/EGLStreamTest.cpp @@ -358,37 +358,79 @@ TEST_P(EGLStreamTest, StreamProducerTextureNV12End2End) { EGLWindow *window = getEGLWindow(); EGLDisplay display = window->getDisplay(); - const char *extensionsString = eglQueryString(display, EGL_EXTENSIONS); - if (strstr(extensionsString, "EGL_ANGLE_stream_producer_d3d_texture_nv12") == nullptr) + if (!eglDisplayExtensionEnabled(display, "EGL_ANGLE_stream_producer_d3d_texture_nv12")) { std::cout << "Stream producer d3d nv12 texture not supported" << std::endl; return; } - // Shader setup - const std::string yuvVS = - "attribute highp vec4 position; varying vec2 texcoord; void main(void)\n" - "{\n" - " gl_Position = position;\n" - " texcoord = (position.xy * 0.5) + 0.5;\n" - " texcoord.y = 1.0 - texcoord.y;\n" - "}\n"; + bool useESSL3Shaders = + getClientVersion() >= 3 && extensionEnabled("GL_OES_EGL_image_external_essl3"); // yuv to rgb conversion shader using Microsoft's given conversion formulas - const std::string yuvPS = - "#extension GL_NV_EGL_stream_consumer_external : require\n" - "precision highp float; varying vec2 texcoord;\n" - "uniform samplerExternalOES y; uniform samplerExternalOES uv\n;" - "void main(void)\n" - "{\n" - " float c = texture2D(y, texcoord).r - (16.0 / 256.0);\n" - " float d = texture2D(uv, texcoord).r - 0.5;\n" - " float e = texture2D(uv, texcoord).g - 0.5;\n" - " float r = 1.164383 * c + 1.596027 * e;\n" - " float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n" - " float b = 1.164383 * c + 2.017232 * d;\n" - " gl_FragColor = vec4(r, g, b, 1.0);\n" - "}\n"; + std::string yuvVS, yuvPS; + if (useESSL3Shaders) + { + yuvVS = + "#version 300 es\n" + "in highp vec4 position;\n" + "out vec2 texcoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = position;\n" + " texcoord = (position.xy * 0.5) + 0.5;\n" + " texcoord.y = 1.0 - texcoord.y;\n" + "}\n"; + yuvPS = + "#version 300 es\n" + "#extension GL_OES_EGL_image_external_essl3 : require\n" + "#extension GL_NV_EGL_stream_consumer_external : require\n" + "precision highp float;\n" + "in vec2 texcoord;\n" + "out vec4 color;\n" + "uniform samplerExternalOES y;\n" + "uniform samplerExternalOES uv\n;" + "void main(void)\n" + "{\n" + " float c = texture(y, texcoord).r - (16.0 / 256.0);\n" + " float d = texture(uv, texcoord).r - 0.5;\n" + " float e = texture(uv, texcoord).g - 0.5;\n" + " float r = 1.164383 * c + 1.596027 * e;\n" + " float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n" + " float b = 1.164383 * c + 2.017232 * d;\n" + " color = vec4(r, g, b, 1.0);\n" + "}\n"; + } + else + { + yuvVS = + "attribute highp vec4 position;\n" + "varying vec2 texcoord;\n" + "void main(void)\n" + "{\n" + " gl_Position = position;\n" + " texcoord = (position.xy * 0.5) + 0.5;\n" + " texcoord.y = 1.0 - texcoord.y;\n" + "}\n"; + + yuvPS = + "#extension GL_NV_EGL_stream_consumer_external : require\n" + "precision highp float;\n" + "varying vec2 texcoord;\n" + "uniform samplerExternalOES y;\n" + "uniform samplerExternalOES uv\n;" + "void main(void)\n" + "{\n" + " float c = texture2D(y, texcoord).r - (16.0 / 256.0);\n" + " float d = texture2D(uv, texcoord).r - 0.5;\n" + " float e = texture2D(uv, texcoord).g - 0.5;\n" + " float r = 1.164383 * c + 1.596027 * e;\n" + " float g = 1.164383 * c - 0.391762 * d - 0.812968 * e;\n" + " float b = 1.164383 * c + 2.017232 * d;\n" + " gl_FragColor = vec4(r, g, b, 1.0);\n" + "}\n"; + } + GLuint program = CompileProgram(yuvVS, yuvPS); ASSERT_NE(0u, program); GLuint yUniform = glGetUniformLocation(program, "y"); diff --git a/src/tests/gl_tests/ImageTest.cpp b/src/tests/gl_tests/ImageTest.cpp index 9f110c8fe..c5e6e1cef 100644 --- a/src/tests/gl_tests/ImageTest.cpp +++ b/src/tests/gl_tests/ImageTest.cpp @@ -40,6 +40,18 @@ class ImageTest : public ANGLETest " texcoord = (position.xy * 0.5) + 0.5;\n" " texcoord.y = 1.0 - texcoord.y;\n" "}\n"; + const std::string vsESSL3Source = + "#version 300 es\n" + "precision highp float;\n" + "in vec4 position;\n" + "out vec2 texcoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = position;\n" + " texcoord = (position.xy * 0.5) + 0.5;\n" + " texcoord.y = 1.0 - texcoord.y;\n" + "}\n"; const std::string textureFSSource = "precision highp float;\n" @@ -50,6 +62,28 @@ class ImageTest : public ANGLETest "{\n" " gl_FragColor = texture2D(tex, texcoord);\n" "}\n"; + const std::string textureExternalFSSource = + "#extension GL_OES_EGL_image_external : require\n" + "precision highp float;\n" + "uniform samplerExternalOES tex;\n" + "varying vec2 texcoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2D(tex, texcoord);\n" + "}\n"; + const std::string textureExternalESSL3FSSource = + "#version 300 es\n" + "#extension GL_OES_EGL_image_external_essl3 : require\n" + "precision highp float;\n" + "uniform samplerExternalOES tex;\n" + "in vec2 texcoord;\n" + "out vec4 color;" + "\n" + "void main()\n" + "{\n" + " color = texture(tex, texcoord);\n" + "}\n"; mTextureProgram = CompileProgram(vsSource, textureFSSource); if (mTextureProgram == 0) @@ -59,6 +93,24 @@ class ImageTest : public ANGLETest mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex"); + if (extensionEnabled("GL_OES_EGL_image_external")) + { + mTextureExternalProgram = CompileProgram(vsSource, textureExternalFSSource); + ASSERT_NE(0u, mTextureExternalProgram) << "shader compilation failed."; + + mTextureExternalUniformLocation = glGetUniformLocation(mTextureExternalProgram, "tex"); + } + + if (extensionEnabled("GL_OES_EGL_image_external_essl3")) + { + mTextureExternalESSL3Program = + CompileProgram(vsESSL3Source, textureExternalESSL3FSSource); + ASSERT_NE(0u, mTextureExternalESSL3Program) << "shader compilation failed."; + + mTextureExternalESSL3UniformLocation = + glGetUniformLocation(mTextureExternalESSL3Program, "tex"); + } + eglCreateImageKHR = reinterpret_cast(eglGetProcAddress("eglCreateImageKHR")); eglDestroyImageKHR = @@ -69,9 +121,11 @@ class ImageTest : public ANGLETest void TearDown() override { - ANGLETest::TearDown(); - glDeleteProgram(mTextureProgram); + glDeleteProgram(mTextureExternalProgram); + glDeleteProgram(mTextureExternalESSL3Program); + + ANGLETest::TearDown(); } void createEGLImage2DTextureSource(size_t width, @@ -245,6 +299,23 @@ class ImageTest : public ANGLETest *outTargetTexture = target; } + void createEGLImageTargetTextureExternal(EGLImageKHR image, GLuint *outTargetTexture) + { + // Create a target texture from the image + GLuint target; + glGenTextures(1, &target); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, target); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); + + // Disable mipmapping + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + ASSERT_GL_NO_ERROR(); + + *outTargetTexture = target; + } + void createEGLImageTargetRenderbuffer(EGLImageKHR image, GLuint *outTargetRenderbuffer) { // Create a target texture from the image @@ -258,19 +329,41 @@ class ImageTest : public ANGLETest *outTargetRenderbuffer = target; } - void verifyResults2D(GLuint texture, GLubyte data[4]) + void verifyResultsTexture(GLuint texture, + GLubyte data[4], + GLenum textureTarget, + GLuint program, + GLuint textureUniform) { // Draw a quad with the target texture - glUseProgram(mTextureProgram); - glBindTexture(GL_TEXTURE_2D, texture); - glUniform1i(mTextureUniformLocation, 0); + glUseProgram(program); + glBindTexture(textureTarget, texture); + glUniform1i(textureUniform, 0); - drawQuad(mTextureProgram, "position", 0.5f); + drawQuad(program, "position", 0.5f); // Expect that the rendered quad has the same color as the source texture EXPECT_PIXEL_EQ(0, 0, data[0], data[1], data[2], data[3]); } + void verifyResults2D(GLuint texture, GLubyte data[4]) + { + verifyResultsTexture(texture, data, GL_TEXTURE_2D, mTextureProgram, + mTextureUniformLocation); + } + + void verifyResultsExternal(GLuint texture, GLubyte data[4]) + { + verifyResultsTexture(texture, data, GL_TEXTURE_EXTERNAL_OES, mTextureExternalProgram, + mTextureExternalUniformLocation); + } + + void verifyResultsExternalESSL3(GLuint texture, GLubyte data[4]) + { + verifyResultsTexture(texture, data, GL_TEXTURE_EXTERNAL_OES, mTextureExternalESSL3Program, + mTextureExternalESSL3UniformLocation); + } + void verifyResultsRenderbuffer(GLuint renderbuffer, GLubyte data[4]) { // Bind the renderbuffer to a framebuffer @@ -298,10 +391,20 @@ class ImageTest : public ANGLETest GLuint mTextureProgram; GLint mTextureUniformLocation; + GLuint mTextureExternalProgram = 0; + GLint mTextureExternalUniformLocation = -1; + + GLuint mTextureExternalESSL3Program = 0; + GLint mTextureExternalESSL3UniformLocation = -1; + PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; }; +class ImageTestES3 : public ImageTest +{ +}; + // Check validation from the EGL_KHR_image_base extension TEST_P(ImageTest, ValidationImageBase) { @@ -755,17 +858,114 @@ TEST_P(ImageTest, ValidationGLEGLImage) // Check validation from the GL_OES_EGL_image_external extension TEST_P(ImageTest, ValidationGLEGLImageExternal) { - // This extension is not implemented anywhere yet. This makes sure that it is tested once it is - // added. - EXPECT_FALSE(extensionEnabled("GL_OES_EGL_image_external")); + if (!extensionEnabled("GL_OES_EGL_image_external")) + { + std::cout << "Test skipped because GL_OES_EGL_image_external is not available." + << std::endl; + return; + } + + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); + + // In the initial state of a TEXTURE_EXTERNAL_OES texture object, the value assigned to + // TEXTURE_MIN_FILTER and TEXTURE_MAG_FILTER is LINEAR, and the s and t wrap modes are both set + // to CLAMP_TO_EDGE + auto getTexParam = [](GLenum target, GLenum pname) + { + GLint value = 0; + glGetTexParameteriv(target, pname, &value); + EXPECT_GL_NO_ERROR(); + return value; + }; + EXPECT_GLENUM_EQ(GL_LINEAR, getTexParam(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER)); + EXPECT_GLENUM_EQ(GL_LINEAR, getTexParam(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER)); + EXPECT_GLENUM_EQ(GL_CLAMP_TO_EDGE, getTexParam(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S)); + EXPECT_GLENUM_EQ(GL_CLAMP_TO_EDGE, getTexParam(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T)); + + // "When is TEXTURE_EXTERNAL_OES only NEAREST and LINEAR are accepted as + // TEXTURE_MIN_FILTER, only CLAMP_TO_EDGE is accepted as TEXTURE_WRAP_S and TEXTURE_WRAP_T, and + // only FALSE is accepted as GENERATE_MIPMAP. Attempting to set other values for + // TEXTURE_MIN_FILTER, TEXTURE_WRAP_S, TEXTURE_WRAP_T, or GENERATE_MIPMAP will result in an + // INVALID_ENUM error. + GLenum validMinFilters[]{ + GL_NEAREST, GL_LINEAR, + }; + for (auto minFilter : validMinFilters) + { + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, minFilter); + EXPECT_GL_NO_ERROR(); + } + + GLenum invalidMinFilters[]{ + GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, + GL_LINEAR_MIPMAP_NEAREST, + }; + for (auto minFilter : invalidMinFilters) + { + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, minFilter); + EXPECT_GL_ERROR(GL_INVALID_ENUM); + } + + GLenum validWrapModes[]{ + GL_CLAMP_TO_EDGE, + }; + for (auto minFilter : validWrapModes) + { + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, minFilter); + EXPECT_GL_NO_ERROR(); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, minFilter); + EXPECT_GL_NO_ERROR(); + } + + GLenum invalidWrapModes[]{ + GL_REPEAT, GL_MIRRORED_REPEAT, + }; + for (auto minFilter : invalidWrapModes) + { + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, minFilter); + EXPECT_GL_ERROR(GL_INVALID_ENUM); + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, minFilter); + EXPECT_GL_ERROR(GL_INVALID_ENUM); + } + + // When is set to TEXTURE_EXTERNAL_OES, GenerateMipmap always fails and generates an + // INVALID_ENUM error. + glGenerateMipmap(GL_TEXTURE_EXTERNAL_OES); + EXPECT_GL_ERROR(GL_INVALID_ENUM); + + glDeleteTextures(1, &texture); } // Check validation from the GL_OES_EGL_image_external_essl3 extension TEST_P(ImageTest, ValidationGLEGLImageExternalESSL3) { - // This extension is not implemented anywhere yet. This makes sure that it is tested once it is - // added. - EXPECT_FALSE(extensionEnabled("GL_OES_EGL_image_external_essl3")); + if (!extensionEnabled("GL_OES_EGL_image_external_essl3")) + { + std::cout << "Test skipped because GL_OES_EGL_image_external is not available." + << std::endl; + return; + } + + // Make sure this extension is not exposed without ES3. + ASSERT_GE(getClientVersion(), 3); + + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); + + // It is an INVALID_OPERATION error to set the TEXTURE_BASE_LEVEL to a value other than zero. + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_BASE_LEVEL, 1); + EXPECT_GL_ERROR(GL_INVALID_OPERATION); + + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_BASE_LEVEL, 10); + EXPECT_GL_ERROR(GL_INVALID_OPERATION); + + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_BASE_LEVEL, 0); + EXPECT_GL_NO_ERROR(); + + glDeleteTextures(1, &texture); } TEST_P(ImageTest, Source2DTarget2D) @@ -834,6 +1034,74 @@ TEST_P(ImageTest, Source2DTargetRenderbuffer) glDeleteRenderbuffers(1, &target); } +TEST_P(ImageTest, Source2DTargetExternal) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_texture_2D_image")) + { + std::cout + << "Test skipped because OES_EGL_image, OES_EGL_image_external, EGL_KHR_image_base or " + "EGL_KHR_gl_texture_2D_image is not available." + << std::endl; + return; + } + + GLubyte data[4] = {255, 0, 255, 255}; + + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImage2DTextureSource(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data, &source, &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target renderbuffer has the same color as the source texture + verifyResultsExternal(target, data); + + // Clean up + glDeleteTextures(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteRenderbuffers(1, &target); +} + +TEST_P(ImageTestES3, Source2DTargetExternalESSL3) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external_essl3") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_texture_2D_image")) + { + std::cout << "Test skipped because OES_EGL_image, OES_EGL_image_external_essl3, " + "EGL_KHR_image_base or " + "EGL_KHR_gl_texture_2D_image is not available." + << std::endl; + return; + } + + GLubyte data[4] = {255, 0, 255, 255}; + + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImage2DTextureSource(1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data, &source, &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target renderbuffer has the same color as the source texture + verifyResultsExternalESSL3(target, data); + + // Clean up + glDeleteTextures(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteRenderbuffers(1, &target); +} + TEST_P(ImageTest, SourceCubeTarget2D) { EGLWindow *window = getEGLWindow(); @@ -916,6 +1184,92 @@ TEST_P(ImageTest, SourceCubeTargetRenderbuffer) } } +// Test cubemap -> external texture EGL images. +TEST_P(ImageTest, SourceCubeTargetExternal) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_texture_cubemap_image")) + { + std::cout + << "Test skipped because OES_EGL_image, OES_EGL_image_external, EGL_KHR_image_base or " + "EGL_KHR_gl_texture_cubemap_image is not available." + << std::endl; + return; + } + + GLubyte data[24] = { + 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, + 0, 0, 255, 255, 0, 255, 0, 255, 0, 0, 0, 255, + }; + + for (EGLenum faceIdx = 0; faceIdx < 6; faceIdx++) + { + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImageCubemapTextureSource( + 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast(data), sizeof(GLubyte) * 4, + EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR + faceIdx, &source, &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target texture has the same color as the source texture + verifyResultsExternal(target, &data[faceIdx * 4]); + + // Clean up + glDeleteTextures(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteRenderbuffers(1, &target); + } +} + +// Test cubemap -> external texture EGL images using ESSL3 shaders. +TEST_P(ImageTestES3, SourceCubeTargetExternalESSL3) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external_essl3") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_texture_cubemap_image")) + { + std::cout << "Test skipped because OES_EGL_image, OES_EGL_image_external_essl3, " + "EGL_KHR_image_base or " + "EGL_KHR_gl_texture_cubemap_image is not available." + << std::endl; + return; + } + + GLubyte data[24] = { + 255, 0, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, + 0, 0, 255, 255, 0, 255, 0, 255, 0, 0, 0, 255, + }; + + for (EGLenum faceIdx = 0; faceIdx < 6; faceIdx++) + { + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImageCubemapTextureSource( + 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast(data), sizeof(GLubyte) * 4, + EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR + faceIdx, &source, &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target texture has the same color as the source texture + verifyResultsExternalESSL3(target, &data[faceIdx * 4]); + + // Clean up + glDeleteTextures(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteRenderbuffers(1, &target); + } +} + TEST_P(ImageTest, Source3DTargetTexture) { EGLWindow *window = getEGLWindow(); @@ -1008,6 +1362,102 @@ TEST_P(ImageTest, Source3DTargetRenderbuffer) } } +// Test 3D -> external texture EGL images. +TEST_P(ImageTest, Source3DTargetExternal) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_texture_3D_image")) + { + std::cout + << "Test skipped because OES_EGL_image, OES_EGL_image_external, EGL_KHR_image_base or " + "EGL_KHR_gl_texture_3D_image is not available." + << std::endl; + return; + } + + if (getClientVersion() < 3 && !extensionEnabled("GL_OES_texture_3D")) + { + std::cout << "Test skipped because 3D textures are not available." << std::endl; + return; + } + + const size_t depth = 2; + GLubyte data[4 * depth] = { + 255, 0, 255, 255, 255, 255, 0, 255, + }; + + for (size_t layer = 0; layer < depth; layer++) + { + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImage3DTextureSource(1, 1, depth, GL_RGBA, GL_UNSIGNED_BYTE, data, layer, &source, + &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target renderbuffer has the same color as the source texture + verifyResultsExternal(target, &data[layer * 4]); + + // Clean up + glDeleteTextures(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteTextures(1, &target); + } +} + +// Test 3D -> external texture EGL images using ESSL3 shaders. +TEST_P(ImageTestES3, Source3DTargetExternalESSL3) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external_essl3") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_texture_3D_image")) + { + std::cout << "Test skipped because OES_EGL_image, OES_EGL_image_external_essl3, " + "EGL_KHR_image_base or " + "EGL_KHR_gl_texture_3D_image is not available." + << std::endl; + return; + } + + if (getClientVersion() < 3 && !extensionEnabled("GL_OES_texture_3D")) + { + std::cout << "Test skipped because 3D textures are not available." << std::endl; + return; + } + + const size_t depth = 2; + GLubyte data[4 * depth] = { + 255, 0, 255, 255, 255, 255, 0, 255, + }; + + for (size_t layer = 0; layer < depth; layer++) + { + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImage3DTextureSource(1, 1, depth, GL_RGBA, GL_UNSIGNED_BYTE, data, layer, &source, + &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target renderbuffer has the same color as the source texture + verifyResultsExternalESSL3(target, &data[layer * 4]); + + // Clean up + glDeleteTextures(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteTextures(1, &target); + } +} + TEST_P(ImageTest, SourceRenderbufferTargetTexture) { EGLWindow *window = getEGLWindow(); @@ -1041,6 +1491,76 @@ TEST_P(ImageTest, SourceRenderbufferTargetTexture) glDeleteTextures(1, &target); } +// Test renderbuffer -> external texture EGL images. +TEST_P(ImageTest, SourceRenderbufferTargetTextureExternal) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_renderbuffer_image")) + { + std::cout + << "Test skipped because OES_EGL_image, OES_EGL_image_external, EGL_KHR_image_base or " + "EGL_KHR_gl_renderbuffer_image is not available." + << std::endl; + return; + } + + GLubyte data[4] = {255, 0, 255, 255}; + + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImageRenderbufferSource(1, 1, GL_RGBA8_OES, data, &source, &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target texture has the same color as the source texture + verifyResultsExternal(target, data); + + // Clean up + glDeleteRenderbuffers(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteTextures(1, &target); +} + +// Test renderbuffer -> external texture EGL images using ESSL3 shaders. +TEST_P(ImageTestES3, SourceRenderbufferTargetTextureExternalESSL3) +{ + EGLWindow *window = getEGLWindow(); + if (!extensionEnabled("OES_EGL_image") || !extensionEnabled("OES_EGL_image_external_essl3") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_image_base") || + !eglDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_renderbuffer_image")) + { + std::cout + << "Test skipped because OES_EGL_image, OES_EGL_image_external, EGL_KHR_image_base or " + "EGL_KHR_gl_renderbuffer_image is not available." + << std::endl; + return; + } + + GLubyte data[4] = {255, 0, 255, 255}; + + // Create the Image + GLuint source; + EGLImageKHR image; + createEGLImageRenderbufferSource(1, 1, GL_RGBA8_OES, data, &source, &image); + + // Create the target + GLuint target; + createEGLImageTargetTextureExternal(image, &target); + + // Expect that the target texture has the same color as the source texture + verifyResultsExternalESSL3(target, data); + + // Clean up + glDeleteRenderbuffers(1, &source); + eglDestroyImageKHR(window->getDisplay(), image); + glDeleteTextures(1, &target); +} + TEST_P(ImageTest, SourceRenderbufferTargetRenderbuffer) { EGLWindow *window = getEGLWindow(); @@ -1449,4 +1969,5 @@ ANGLE_INSTANTIATE_TEST(ImageTest, ES3_OPENGL(), ES2_OPENGLES(), ES3_OPENGLES()); +ANGLE_INSTANTIATE_TEST(ImageTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); }