Commit 62b72552 by Mohan Maiya Committed by Commit Bot

Add support for EXT_EGL_image_external_wrap_modes

Allows for more wrap modes to TEXTURE_EXTERNAL_OES textures Test: angle_end2end_tests --gtest_filter=ExternalWrapTest.* Bug: angleproject:4443 Change-Id: I37bde091b166d7471c13c14fd6b0174136b52ecf Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2103433 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 32c1bf54
......@@ -927,6 +927,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_OES_EGL_image"] = enableableExtension(&Extensions::eglImageOES);
map["GL_OES_EGL_image_external"] = enableableExtension(&Extensions::eglImageExternalOES);
map["GL_OES_EGL_image_external_essl3"] = enableableExtension(&Extensions::eglImageExternalEssl3OES);
map["GL_EXT_EGL_image_external_wrap_modes"] = enableableExtension(&Extensions::eglImageExternalWrapModesEXT);
map["GL_OES_EGL_sync"] = esOnlyExtension(&Extensions::eglSyncOES);
map["GL_EXT_memory_object"] = enableableExtension(&Extensions::memoryObject);
map["GL_EXT_memory_object_fd"] = enableableExtension(&Extensions::memoryObjectFd);
......
......@@ -392,6 +392,9 @@ struct Extensions
// GL_OES_EGL_image_external_essl3
bool eglImageExternalEssl3OES = false;
// GL_EXT_EGL_image_external_wrap_modes
bool eglImageExternalWrapModesEXT = false;
// GL_OES_EGL_sync
bool eglSyncOES = false;
......
......@@ -271,7 +271,7 @@ SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &sam
}
bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
const State &data) const
const State &state) const
{
if (mBaseLevel > mMaxLevel)
{
......@@ -298,12 +298,13 @@ bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
// filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
// incomplete texture. So, we ignore filtering for multisample texture completeness here.
if (!IsMultisampled(mType) &&
!baseImageDesc.format.info->filterSupport(data.getClientVersion(), data.getExtensions()) &&
!baseImageDesc.format.info->filterSupport(state.getClientVersion(),
state.getExtensions()) &&
!IsPointSampled(samplerState))
{
return false;
}
bool npotSupport = data.getExtensions().textureNPOTOES || data.getClientMajorVersion() >= 3;
bool npotSupport = state.getExtensions().textureNPOTOES || state.getClientMajorVersion() >= 3;
if (!npotSupport)
{
if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
......@@ -343,15 +344,20 @@ bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
// 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.
// texture and EXT_EGL_image_external_wrap_modes is not enabled, 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 (mType == TextureType::External)
{
if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
if (!state.getExtensions().eglImageExternalWrapModesEXT)
{
return false;
if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
{
return false;
}
}
if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
......@@ -366,7 +372,7 @@ bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
// MODE is NONE, and either the magnification filter is not NEAREST or the mini-
// fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
data.getClientMajorVersion() >= 3)
state.getClientMajorVersion() >= 3)
{
// Note: we restrict this validation to sized types. For the OES_depth_textures
// extension, due to some underspecification problems, we must allow linear filtering
......
......@@ -159,7 +159,7 @@ class TextureState final : private angle::NonCopyable
friend class rx::TextureGL;
friend bool operator==(const TextureState &a, const TextureState &b);
bool computeSamplerCompleteness(const SamplerState &samplerState, const State &data) const;
bool computeSamplerCompleteness(const SamplerState &samplerState, const State &state) const;
bool computeMipmapCompleteness() const;
bool computeLevelCompleteness(TextureTarget target, size_t level) const;
SamplerFormat computeRequiredSamplerFormat(const SamplerState &samplerState) const;
......
......@@ -1623,6 +1623,7 @@ void GenerateCaps(ID3D11Device *device,
extensions->debugMarker = true;
extensions->eglImageOES = true;
extensions->eglImageExternalOES = true;
extensions->eglImageExternalWrapModesEXT = true;
extensions->eglImageExternalEssl3OES = true;
extensions->eglStreamConsumerExternalNV = true;
extensions->unpackSubimage = true;
......
......@@ -1237,6 +1237,8 @@ void GenerateCaps(const FunctionsGL *functions,
functions->hasGLESExtension("GL_EXT_debug_marker");
extensions->eglImageOES = functions->hasGLESExtension("GL_OES_EGL_image");
extensions->eglImageExternalOES = functions->hasGLESExtension("GL_OES_EGL_image_external");
extensions->eglImageExternalWrapModesEXT =
functions->hasExtension("GL_EXT_EGL_image_external_wrap_modes");
extensions->eglImageExternalEssl3OES =
functions->hasGLESExtension("GL_OES_EGL_image_external_essl3");
......
......@@ -90,9 +90,10 @@ void RendererVk::ensureCapsInitialized() const
// Enable EXT_blend_minmax
mNativeExtensions.blendMinMax = true;
mNativeExtensions.eglImageOES = true;
mNativeExtensions.eglImageExternalOES = true;
mNativeExtensions.eglImageExternalEssl3OES = true;
mNativeExtensions.eglImageOES = true;
mNativeExtensions.eglImageExternalOES = true;
mNativeExtensions.eglImageExternalWrapModesEXT = true;
mNativeExtensions.eglImageExternalEssl3OES = true;
mNativeExtensions.memoryObject = true;
mNativeExtensions.memoryObjectFd = getFeatures().supportsExternalMemoryFd.enabled;
......
......@@ -5844,8 +5844,9 @@ bool ValidateTexParameterBase(const Context *context,
case GL_TEXTURE_WRAP_T:
case GL_TEXTURE_WRAP_R:
{
bool restrictedWrapModes =
target == TextureType::External || target == TextureType::Rectangle;
bool restrictedWrapModes = ((target == TextureType::External &&
!context->getExtensions().eglImageExternalWrapModesEXT) ||
target == TextureType::Rectangle);
if (!ValidateTextureWrapModeValue(context, params, restrictedWrapModes))
{
return false;
......
......@@ -55,6 +55,7 @@ angle_end2end_tests_sources = [
"gl_tests/DrawElementsTest.cpp",
"gl_tests/ETCTextureTest.cpp",
"gl_tests/ExplicitContextTest.cpp",
"gl_tests/ExternalWrapTest.cpp",
"gl_tests/FenceSyncTests.cpp",
"gl_tests/FloatingPointSurfaceTest.cpp",
"gl_tests/FramebufferMixedSamplesTest.cpp",
......
//
// Copyright 2020 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.
//
// ExternalWrapTest:
// Tests EXT_EGL_image_external_wrap_modes
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include "util/EGLWindow.h"
constexpr int kPixelThreshold = 1;
namespace angle
{
class ExternalWrapTest : public ANGLETest
{
protected:
ExternalWrapTest() : mProgram(0), mSourceTexture(0), mExternalImage(0), mExternalTexture(0)
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setConfigDepthBits(24);
}
void testSetUp() override
{
if (!IsGLExtensionEnabled("GL_OES_EGL_image_external"))
{
return;
}
const char *vertSrc = R"(precision highp float;
attribute vec4 a_position;
varying vec2 v_texcoord;
uniform vec2 u_offset;
void main()
{
gl_Position = a_position;
v_texcoord = (a_position.xy * 0.5) + 0.5 + u_offset;
}
)";
const char *fragSrc = R"(#extension GL_OES_EGL_image_external : require
precision highp float;
uniform samplerExternalOES s_tex;
varying vec2 v_texcoord;
void main()
{
gl_FragColor = texture2D(s_tex, v_texcoord);
}
)";
mProgram = CompileProgram(vertSrc, fragSrc);
ASSERT_GL_NO_ERROR();
ASSERT_NE(mProgram, 0u);
constexpr GLsizei texSize = 32;
GLubyte data[texSize * texSize * 4];
for (int y = 0; y < texSize; y++)
{
float green = static_cast<float>(y) / texSize;
for (int x = 0; x < texSize; x++)
{
float red = static_cast<float>(x) / texSize;
data[(y * texSize + x) * 4 + 0] = static_cast<GLubyte>(red * 255);
data[(y * texSize + x) * 4 + 1] = static_cast<GLubyte>(green * 255);
data[(y * texSize + x) * 4 + 2] = 0;
data[(y * texSize + x) * 4 + 3] = 255;
}
}
glGenTextures(1, &mSourceTexture);
glBindTexture(GL_TEXTURE_2D, mSourceTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texSize, texSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
glGenTextures(1, &mExternalTexture);
ASSERT_GL_NO_ERROR();
}
void testTearDown() override
{
if (mProgram != 0)
{
glDeleteProgram(mProgram);
}
if (mExternalTexture != 0)
{
glDeleteTextures(1, &mExternalTexture);
}
if (mSourceTexture != 0)
{
glDeleteTextures(1, &mSourceTexture);
}
}
void createExternalTexture()
{
ASSERT_TRUE(IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
"EGL_KHR_gl_texture_2D_image"));
ASSERT_TRUE(IsGLExtensionEnabled("GL_OES_EGL_image_external"));
EGLWindow *window = getEGLWindow();
EGLint attribs[] = {
EGL_IMAGE_PRESERVED,
EGL_TRUE,
EGL_NONE,
};
EGLImageKHR image =
eglCreateImageKHR(window->getDisplay(), window->getContext(), EGL_GL_TEXTURE_2D_KHR,
reinterpret_cast<EGLClientBuffer>(mSourceTexture), attribs);
ASSERT_EGL_SUCCESS();
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
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();
}
GLuint mProgram;
GLuint mTextureUniformLocation;
GLuint mOffsetUniformLocation;
GLuint mSourceTexture;
EGLImageKHR mExternalImage;
GLuint mExternalTexture;
};
// Test the default sampling behavior of an external texture
TEST_P(ExternalWrapTest, NoWrap)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_EGL_image_external"));
ANGLE_SKIP_TEST_IF(
!IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_gl_texture_2D_image"));
createExternalTexture();
ASSERT_NE(mProgram, 0u);
glUseProgram(mProgram);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture);
glUniform2f(glGetUniformLocation(mProgram, "u_offset"), 0.0, 0.0);
drawQuad(mProgram, "a_position", 0);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0, 0, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 0, GLColor(247, 0, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(0, 127, GLColor(0, 247, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 127, GLColor(247, 247, 0, 255), kPixelThreshold);
}
// Test that external textures are sampled correctly when used with GL_CLAMP_TO_EDGE
TEST_P(ExternalWrapTest, ClampToEdge)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_EGL_image_external"));
ANGLE_SKIP_TEST_IF(
!IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_gl_texture_2D_image"));
createExternalTexture();
ASSERT_NE(mProgram, 0u);
glUseProgram(mProgram);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform2f(glGetUniformLocation(mProgram, "u_offset"), 0.5, 0.5);
drawQuad(mProgram, "a_position", 0);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(127, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 0, GLColor(247, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(0, 127, GLColor(127, 247, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 127, GLColor(247, 247, 0, 255), kPixelThreshold);
}
// Test that external textures are sampled correctly when used with GL_REPEAT
TEST_P(ExternalWrapTest, Repeat)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_EGL_image_external"));
ANGLE_SKIP_TEST_IF(
!IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_gl_texture_2D_image"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_EGL_image_external_wrap_modes"));
createExternalTexture();
ASSERT_NE(mProgram, 0u);
glUseProgram(mProgram);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_REPEAT);
glUniform2f(glGetUniformLocation(mProgram, "u_offset"), 0.5, 0.5);
drawQuad(mProgram, "a_position", 0);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(127, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 0, GLColor(119, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(0, 127, GLColor(127, 119, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 127, GLColor(119, 119, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(63, 63, GLColor(247, 247, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(64, 63, GLColor(0, 247, 0, 255), kPixelThreshold);
}
// Test that external textures are sampled correctly when used with GL_MIRRORED_REPEAT
TEST_P(ExternalWrapTest, MirroredRepeat)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_EGL_image_external"));
ANGLE_SKIP_TEST_IF(
!IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_gl_texture_2D_image"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_EGL_image_external_wrap_modes"));
createExternalTexture();
ASSERT_NE(mProgram, 0u);
glUseProgram(mProgram);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mExternalTexture);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glUniform2f(glGetUniformLocation(mProgram, "u_offset"), 0.5, 0.5);
drawQuad(mProgram, "a_position", 0);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(127, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 0, GLColor(127, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(0, 127, GLColor(127, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(127, 127, GLColor(127, 127, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(63, 63, GLColor(247, 247, 0, 255), kPixelThreshold);
EXPECT_PIXEL_COLOR_NEAR(64, 63, GLColor(247, 247, 0, 255), kPixelThreshold);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ExternalWrapTest);
} // namespace angle
......@@ -1019,24 +1019,38 @@ TEST_P(ImageTest, ValidationGLEGLImageExternal)
GLenum validWrapModes[]{
GL_CLAMP_TO_EDGE,
};
for (auto minFilter : validWrapModes)
for (auto wrapMode : validWrapModes)
{
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, minFilter);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, wrapMode);
EXPECT_GL_NO_ERROR();
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, minFilter);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, wrapMode);
EXPECT_GL_NO_ERROR();
}
GLenum invalidWrapModes[]{
GL_REPEAT,
GL_MIRRORED_REPEAT,
};
for (auto minFilter : invalidWrapModes)
if (IsGLExtensionEnabled("GL_EXT_EGL_image_external_wrap_modes"))
{
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);
GLenum validWrapModesEXT[]{GL_REPEAT, GL_MIRRORED_REPEAT};
for (auto wrapMode : validWrapModesEXT)
{
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, wrapMode);
EXPECT_GL_NO_ERROR();
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, wrapMode);
EXPECT_GL_NO_ERROR();
}
}
else
{
GLenum invalidWrapModes[]{
GL_REPEAT,
GL_MIRRORED_REPEAT,
};
for (auto wrapMode : invalidWrapModes)
{
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, wrapMode);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, wrapMode);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
}
}
// When <target> is set to TEXTURE_EXTERNAL_OES, GenerateMipmap always fails and generates an
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment