Commit 336e8915 by James Darpinian Committed by Commit Bot

Workaround broken copyTexImage2D on iOS

Use BlitGL to reimplement copyTex[Sub]Image2D on iOS. Bug: angleproject:4674 Change-Id: Ie3018d6d33da57797162922410f76557124df4b6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2222718 Commit-Queue: James Darpinian <jdarpinian@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 4038679a
...@@ -448,6 +448,11 @@ struct FeaturesGL : FeatureSetBase ...@@ -448,6 +448,11 @@ struct FeaturesGL : FeatureSetBase
"decode_encode_srgb_for_generatemipmap", FeatureCategory::OpenGLWorkarounds, "decode_encode_srgb_for_generatemipmap", FeatureCategory::OpenGLWorkarounds,
"Decode and encode before generateMipmap for srgb format textures.", &members, "Decode and encode before generateMipmap for srgb format textures.", &members,
"http://anglebug.com/4646"}; "http://anglebug.com/4646"};
Feature emulateCopyTexImage2DFromRenderbuffers = {
"emulate_copyteximage2d_from_renderbuffers", FeatureCategory::OpenGLWorkarounds,
"CopyTexImage2D spuriously returns errors on iOS when copying from renderbuffers.",
&members, "https://anglebug.com/4674"};
}; };
inline FeaturesGL::FeaturesGL() = default; inline FeaturesGL::FeaturesGL() = default;
......
...@@ -395,12 +395,53 @@ angle::Result BlitGL::copySubImageToLUMAWorkaroundTexture(const gl::Context *con ...@@ -395,12 +395,53 @@ angle::Result BlitGL::copySubImageToLUMAWorkaroundTexture(const gl::Context *con
angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context, angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
const gl::Framebuffer *source, const gl::Framebuffer *source,
const GLuint destTexture,
const gl::TextureTarget destTarget,
const size_t destLevel,
const gl::Rectangle &sourceAreaIn,
const gl::Rectangle &destAreaIn,
GLenum filter,
bool writeAlpha)
{
ANGLE_TRY(initializeResources(context));
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
ToGLenum(destTarget), destTexture,
static_cast<GLint>(destLevel)));
GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
if (status != GL_FRAMEBUFFER_COMPLETE)
{
return angle::Result::Stop;
}
angle::Result result = blitColorBufferWithShader(context, source, mScratchFBO, sourceAreaIn,
destAreaIn, filter, writeAlpha);
// Unbind the texture from the the scratch framebuffer.
ANGLE_GL_TRY(context, mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0));
return result;
}
angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
const gl::Framebuffer *source,
const gl::Framebuffer *dest, const gl::Framebuffer *dest,
const gl::Rectangle &sourceAreaIn, const gl::Rectangle &sourceAreaIn,
const gl::Rectangle &destAreaIn, const gl::Rectangle &destAreaIn,
GLenum filter, GLenum filter,
bool writeAlpha) bool writeAlpha)
{ {
const FramebufferGL *destGL = GetImplAs<FramebufferGL>(dest);
return blitColorBufferWithShader(context, source, destGL->getFramebufferID(), sourceAreaIn,
destAreaIn, filter, writeAlpha);
}
angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
const gl::Framebuffer *source,
const GLuint destFramebuffer,
const gl::Rectangle &sourceAreaIn,
const gl::Rectangle &destAreaIn,
GLenum filter,
bool writeAlpha)
{
ANGLE_TRY(initializeResources(context)); ANGLE_TRY(initializeResources(context));
BlitProgram *blitProgram = nullptr; BlitProgram *blitProgram = nullptr;
...@@ -505,8 +546,7 @@ angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context, ...@@ -505,8 +546,7 @@ angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0)); ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0)); ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
const FramebufferGL *destGL = GetImplAs<FramebufferGL>(dest); mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, destFramebuffer);
mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, destGL->getFramebufferID());
mStateManager->bindVertexArray(mVAO, 0); mStateManager->bindVertexArray(mVAO, 0);
ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3)); ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
......
...@@ -73,6 +73,24 @@ class BlitGL : angle::NonCopyable ...@@ -73,6 +73,24 @@ class BlitGL : angle::NonCopyable
GLenum filter, GLenum filter,
bool writeAlpha); bool writeAlpha);
angle::Result blitColorBufferWithShader(const gl::Context *context,
const gl::Framebuffer *source,
const GLuint destFramebuffer,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
GLenum filter,
bool writeAlpha);
angle::Result blitColorBufferWithShader(const gl::Context *context,
const gl::Framebuffer *source,
const GLuint destTexture,
const gl::TextureTarget destTarget,
const size_t destLevel,
const gl::Rectangle &sourceArea,
const gl::Rectangle &destArea,
GLenum filter,
bool writeAlpha);
angle::Result copySubTexture(const gl::Context *context, angle::Result copySubTexture(const gl::Context *context,
TextureGL *source, TextureGL *source,
size_t sourceLevel, size_t sourceLevel,
......
...@@ -713,7 +713,17 @@ angle::Result TextureGL::copyImage(const gl::Context *context, ...@@ -713,7 +713,17 @@ angle::Result TextureGL::copyImage(const gl::Context *context,
ASSERT(nativegl::UseTexImage2D(getType())); ASSERT(nativegl::UseTexImage2D(getType()));
stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER,
sourceFramebufferGL->getFramebufferID()); sourceFramebufferGL->getFramebufferID());
if (requiresInitialization) if (features.emulateCopyTexImage2DFromRenderbuffers.enabled && readBuffer &&
readBuffer->type() == GL_RENDERBUFFER)
{
BlitGL *blitter = GetBlitGL(context);
ANGLE_TRY(blitter->blitColorBufferWithShader(
context, source, mTextureID, target, level, clippedArea,
gl::Rectangle(destOffset.x, destOffset.y, clippedArea.width,
clippedArea.height),
GL_NEAREST, true));
}
else if (requiresInitialization)
{ {
ANGLE_GL_TRY(context, functions->copyTexSubImage2D( ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
ToGLenum(target), static_cast<GLint>(level), destOffset.x, ToGLenum(target), static_cast<GLint>(level), destOffset.x,
...@@ -781,10 +791,24 @@ angle::Result TextureGL::copySubImage(const gl::Context *context, ...@@ -781,10 +791,24 @@ angle::Result TextureGL::copySubImage(const gl::Context *context,
if (nativegl::UseTexImage2D(getType())) if (nativegl::UseTexImage2D(getType()))
{ {
ASSERT(clippedOffset.z == 0); ASSERT(clippedOffset.z == 0);
ANGLE_GL_TRY(context, functions->copyTexSubImage2D( if (features.emulateCopyTexImage2DFromRenderbuffers.enabled &&
ToGLenum(target), static_cast<GLint>(level), clippedOffset.x, source->getReadColorAttachment() &&
clippedOffset.y, clippedArea.x, clippedArea.y, source->getReadColorAttachment()->type() == GL_RENDERBUFFER)
clippedArea.width, clippedArea.height)); {
BlitGL *blitter = GetBlitGL(context);
ANGLE_TRY(blitter->blitColorBufferWithShader(
context, source, mTextureID, target, level, clippedArea,
gl::Rectangle(clippedOffset.x, clippedOffset.y, clippedArea.width,
clippedArea.height),
GL_NEAREST, true));
}
else
{
ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
ToGLenum(target), static_cast<GLint>(level),
clippedOffset.x, clippedOffset.y, clippedArea.x,
clippedArea.y, clippedArea.width, clippedArea.height));
}
} }
else else
{ {
......
...@@ -1746,6 +1746,14 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature ...@@ -1746,6 +1746,14 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature
ANGLE_FEATURE_CONDITION(features, encodeAndDecodeSRGBForGenerateMipmap, ANGLE_FEATURE_CONDITION(features, encodeAndDecodeSRGBForGenerateMipmap,
IsApple() && functions->standard == STANDARD_GL_DESKTOP); IsApple() && functions->standard == STANDARD_GL_DESKTOP);
// anglebug.com/4674
// The (redundant) explicit exclusion of Windows AMD is because the workaround fails
// Texture2DRGTest.TextureRGUNormTest on that platform, and the test is skipped. If
// you'd like to enable the workaround on Windows AMD, please fix the test first.
ANGLE_FEATURE_CONDITION(
features, emulateCopyTexImage2DFromRenderbuffers,
IsApple() && functions->standard == STANDARD_GL_ES && !(isAMD && IsWindows()));
} }
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features) void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
......
...@@ -895,7 +895,12 @@ ANGLE_INSTANTIATE_TEST(CopyTexImageTest, ...@@ -895,7 +895,12 @@ ANGLE_INSTANTIATE_TEST(CopyTexImageTest,
ES2_OPENGL(), ES2_OPENGL(),
ES2_OPENGLES(), ES2_OPENGLES(),
ES2_VULKAN(), ES2_VULKAN(),
ES3_VULKAN()); ES3_VULKAN(),
WithEmulateCopyTexImage2DFromRenderbuffers(ES2_OPENGL()),
ANGLE_INSTANTIATE_TEST_ES3(CopyTexImageTestES3); WithEmulateCopyTexImage2DFromRenderbuffers(ES2_OPENGLES()));
ANGLE_INSTANTIATE_TEST(CopyTexImageTestES3,
ANGLE_ALL_TEST_PLATFORMS_ES3,
WithEmulateCopyTexImage2DFromRenderbuffers(ES3_OPENGL()),
WithEmulateCopyTexImage2DFromRenderbuffers(ES3_OPENGLES()));
} // namespace angle } // namespace angle
...@@ -4536,6 +4536,10 @@ class Texture2DRGTest : public Texture2DTest ...@@ -4536,6 +4536,10 @@ class Texture2DRGTest : public Texture2DTest
TEST_P(Texture2DRGTest, TextureRGUNormTest) TEST_P(Texture2DRGTest, TextureRGUNormTest)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_rg")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_rg"));
// This workaround causes a GL error on Windows AMD, which is likely a driver bug.
// The workaround is not intended to be enabled in this configuration so skip it.
ANGLE_SKIP_TEST_IF(GetParam().eglParameters.emulateCopyTexImage2DFromRenderbuffers &&
IsWindows() && IsAMD());
GLubyte pixelValue = 0xab; GLubyte pixelValue = 0xab;
GLubyte imageData[] = {pixelValue, pixelValue}; GLubyte imageData[] = {pixelValue, pixelValue};
...@@ -6204,7 +6208,13 @@ TEST_P(ETC1CompressedTextureTest, ETC1ShrinkThenGrowMaxLevels) ...@@ -6204,7 +6208,13 @@ TEST_P(ETC1CompressedTextureTest, ETC1ShrinkThenGrowMaxLevels)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2(Texture2DTest); #define ES2_EMULATE_COPY_TEX_IMAGE() \
WithEmulateCopyTexImage2DFromRenderbuffers(ES2_OPENGL()), \
WithEmulateCopyTexImage2DFromRenderbuffers(ES2_OPENGLES())
#define ES3_EMULATE_COPY_TEX_IMAGE() \
WithEmulateCopyTexImage2DFromRenderbuffers(ES3_OPENGL()), \
WithEmulateCopyTexImage2DFromRenderbuffers(ES3_OPENGLES())
ANGLE_INSTANTIATE_TEST(Texture2DTest, ANGLE_ALL_TEST_PLATFORMS_ES2, ES2_EMULATE_COPY_TEX_IMAGE());
ANGLE_INSTANTIATE_TEST_ES2(TextureCubeTest); ANGLE_INSTANTIATE_TEST_ES2(TextureCubeTest);
ANGLE_INSTANTIATE_TEST_ES2(Texture2DTestWithDrawScale); ANGLE_INSTANTIATE_TEST_ES2(Texture2DTestWithDrawScale);
ANGLE_INSTANTIATE_TEST_ES2(Sampler2DAsFunctionParameterTest); ANGLE_INSTANTIATE_TEST_ES2(Sampler2DAsFunctionParameterTest);
...@@ -6229,7 +6239,11 @@ ANGLE_INSTANTIATE_TEST_ES3(TextureBorderClampTestES3); ...@@ -6229,7 +6239,11 @@ ANGLE_INSTANTIATE_TEST_ES3(TextureBorderClampTestES3);
ANGLE_INSTANTIATE_TEST_ES3(TextureBorderClampIntegerTestES3); ANGLE_INSTANTIATE_TEST_ES3(TextureBorderClampIntegerTestES3);
ANGLE_INSTANTIATE_TEST_ES2(TextureLimitsTest); ANGLE_INSTANTIATE_TEST_ES2(TextureLimitsTest);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DNorm16TestES3); ANGLE_INSTANTIATE_TEST_ES3(Texture2DNorm16TestES3);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(Texture2DRGTest); ANGLE_INSTANTIATE_TEST(Texture2DRGTest,
ANGLE_ALL_TEST_PLATFORMS_ES2,
ANGLE_ALL_TEST_PLATFORMS_ES3,
ES2_EMULATE_COPY_TEX_IMAGE(),
ES3_EMULATE_COPY_TEX_IMAGE());
ANGLE_INSTANTIATE_TEST_ES3(Texture2DFloatTestES3); ANGLE_INSTANTIATE_TEST_ES3(Texture2DFloatTestES3);
ANGLE_INSTANTIATE_TEST_ES2(Texture2DFloatTestES2); ANGLE_INSTANTIATE_TEST_ES2(Texture2DFloatTestES2);
ANGLE_INSTANTIATE_TEST_ES3(TextureCubeTestES3); ANGLE_INSTANTIATE_TEST_ES3(TextureCubeTestES3);
......
...@@ -204,6 +204,11 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp) ...@@ -204,6 +204,11 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp)
stream << "_AllocateNonZeroMemory"; stream << "_AllocateNonZeroMemory";
} }
if (pp.eglParameters.emulateCopyTexImage2DFromRenderbuffers == EGL_TRUE)
{
stream << "_EmulateCopyTexImage2DFromRenderbuffers";
}
return stream; return stream;
} }
......
...@@ -219,6 +219,14 @@ inline PlatformParameters WithAllocateNonZeroMemory(const PlatformParameters &pa ...@@ -219,6 +219,14 @@ inline PlatformParameters WithAllocateNonZeroMemory(const PlatformParameters &pa
return allocateNonZero; return allocateNonZero;
} }
inline PlatformParameters WithEmulateCopyTexImage2DFromRenderbuffers(
const PlatformParameters &params)
{
PlatformParameters p = params;
p.eglParameters.emulateCopyTexImage2DFromRenderbuffers = EGL_TRUE;
return p;
}
inline PlatformParameters WithRobustness(const PlatformParameters &params) inline PlatformParameters WithRobustness(const PlatformParameters &params)
{ {
PlatformParameters withRobustness = params; PlatformParameters withRobustness = params;
......
...@@ -60,20 +60,22 @@ struct EGLPlatformParameters ...@@ -60,20 +60,22 @@ struct EGLPlatformParameters
{ {
return std::tie(renderer, majorVersion, minorVersion, deviceType, presentPath, return std::tie(renderer, majorVersion, minorVersion, deviceType, presentPath,
debugLayersEnabled, contextVirtualization, transformFeedbackFeature, debugLayersEnabled, contextVirtualization, transformFeedbackFeature,
allocateNonZeroMemoryFeature, platformMethods, robustness); allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers,
platformMethods, robustness);
} }
EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
EGLint majorVersion = EGL_DONT_CARE; EGLint majorVersion = EGL_DONT_CARE;
EGLint minorVersion = EGL_DONT_CARE; EGLint minorVersion = EGL_DONT_CARE;
EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE; EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
EGLint presentPath = EGL_DONT_CARE; EGLint presentPath = EGL_DONT_CARE;
EGLint debugLayersEnabled = EGL_DONT_CARE; EGLint debugLayersEnabled = EGL_DONT_CARE;
EGLint contextVirtualization = EGL_DONT_CARE; EGLint contextVirtualization = EGL_DONT_CARE;
EGLint robustness = EGL_DONT_CARE; EGLint robustness = EGL_DONT_CARE;
EGLint transformFeedbackFeature = EGL_DONT_CARE; EGLint transformFeedbackFeature = EGL_DONT_CARE;
EGLint allocateNonZeroMemoryFeature = EGL_DONT_CARE; EGLint allocateNonZeroMemoryFeature = EGL_DONT_CARE;
angle::PlatformMethods *platformMethods = nullptr; EGLint emulateCopyTexImage2DFromRenderbuffers = EGL_DONT_CARE;
angle::PlatformMethods *platformMethods = nullptr;
}; };
inline bool operator<(const EGLPlatformParameters &a, const EGLPlatformParameters &b) inline bool operator<(const EGLPlatformParameters &a, const EGLPlatformParameters &b)
......
...@@ -191,6 +191,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow, ...@@ -191,6 +191,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow,
disabledFeatureOverrides.push_back("allocate_non_zero_memory"); disabledFeatureOverrides.push_back("allocate_non_zero_memory");
} }
if (params.emulateCopyTexImage2DFromRenderbuffers == EGL_TRUE)
{
enabledFeatureOverrides.push_back("emulate_copyteximage2d_from_renderbuffers");
}
if (!disabledFeatureOverrides.empty()) if (!disabledFeatureOverrides.empty())
{ {
if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr) if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr)
......
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