Work around Mac glGenerateMipmap with missing levels bug.

Some Mac GL drivers fail to generate mipmaps if level zero is not set
before the texture is first used, all mipmap data is black.

To work around this, whenever a texture level is allocated, ensure that
level zero is also allocated with at least a 1x1 image.

Bug: angleproject:5223
Change-Id: If1a728e017dec600c77a54f7ae185b719aaaae84
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2497569
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
This commit is contained in:
Geoff Lang 2020-10-26 14:35:14 -04:00 коммит произвёл Commit Bot
Родитель 5c2db1c5e5
Коммит f02a6e0c7f
4 изменённых файлов: 63 добавлений и 2 удалений

Просмотреть файл

@ -499,6 +499,12 @@ struct FeaturesGL : FeatureSetBase
"keep_buffer_shadow_copy", FeatureCategory::OpenGLWorkarounds, "keep_buffer_shadow_copy", FeatureCategory::OpenGLWorkarounds,
"Maintain a shadow copy of buffer data when the GL API does not permit reading data back.", "Maintain a shadow copy of buffer data when the GL API does not permit reading data back.",
&members}; &members};
// glGenerateMipmap fails if the zero texture level is not set on some Mac drivers
Feature setZeroLevelBeforeGenerateMipmap = {
"set_zero_level_before_generating_mipmap", FeatureCategory::OpenGLWorkarounds,
"glGenerateMipmap fails if the zero texture level is not set on some Mac drivers.",
&members};
}; };
inline FeaturesGL::FeaturesGL() = default; inline FeaturesGL::FeaturesGL() = default;

Просмотреть файл

@ -265,8 +265,29 @@ angle::Result TextureGL::setImageHelper(const gl::Context *context,
texImageFormat.type, pixels)); texImageFormat.type, pixels));
} }
setLevelInfo(context, target, level, 1, LevelInfoGL levelInfo = GetLevelInfo(features, internalFormat, texImageFormat.internalFormat);
GetLevelInfo(features, internalFormat, texImageFormat.internalFormat)); setLevelInfo(context, target, level, 1, levelInfo);
if (features.setZeroLevelBeforeGenerateMipmap.enabled && getType() == gl::TextureType::_2D &&
level != 0 && mLevelInfo[0].nativeInternalFormat == GL_NONE)
{
// Only fill level zero if it's possible that mipmaps can be generated with this format
const gl::InternalFormat &internalFormatInfo =
gl::GetInternalFormatInfo(internalFormat, type);
if (!internalFormatInfo.sized ||
(internalFormatInfo.filterSupport(context->getClientVersion(),
context->getExtensions()) &&
internalFormatInfo.textureAttachmentSupport(context->getClientVersion(),
context->getExtensions())))
{
ANGLE_GL_TRY_ALWAYS_CHECK(
context,
functions->texImage2D(nativegl::GetTextureBindingTarget(target), 0,
texImageFormat.internalFormat, 1, 1, 0, texImageFormat.format,
texImageFormat.type, nullptr));
setLevelInfo(context, target, 0, 1, levelInfo);
}
}
return angle::Result::Continue; return angle::Result::Continue;
} }

Просмотреть файл

@ -1837,6 +1837,8 @@ void InitializeFeatures(const FunctionsGL *functions, angle::FeaturesGL *feature
ANGLE_FEATURE_CONDITION(features, disableSyncControlSupport, false); ANGLE_FEATURE_CONDITION(features, disableSyncControlSupport, false);
ANGLE_FEATURE_CONDITION(features, keepBufferShadowCopy, !CanMapBufferForRead(functions)); ANGLE_FEATURE_CONDITION(features, keepBufferShadowCopy, !CanMapBufferForRead(functions));
ANGLE_FEATURE_CONDITION(features, setZeroLevelBeforeGenerateMipmap, IsApple());
} }
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features) void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)

Просмотреть файл

@ -605,6 +605,38 @@ TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red); EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
} }
// Test generating mipmaps with base level and max level set. Ported from part of the
// conformance2/textures/misc/tex-mipmap-levels WebGL2 test.
TEST_P(MipmapTestES3, GenerateMipmapPartialLevels)
{
const std::vector<GLColor> kRedData(64, GLColor::red);
const std::vector<GLColor> kGreenData(16, GLColor::green);
const std::vector<GLColor> kBlueData(4, GLColor::blue);
// Initialize mips 2 to 4
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, kRedData.data());
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, kGreenData.data());
glTexImage2D(GL_TEXTURE_2D, 4, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kBlueData.data());
// Set base and max levels
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
// Verify the data
clearAndDrawQuad(m2DProgram, 2, 2);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
// Test that generateMipmap works with partial levels.
glGenerateMipmap(GL_TEXTURE_2D);
clearAndDrawQuad(m2DProgram, 2, 2);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
// This test generates mipmaps for a 1x1 texture, which should be a no-op. // This test generates mipmaps for a 1x1 texture, which should be a no-op.
TEST_P(MipmapTestES3, GenerateMipmap1x1Texture) TEST_P(MipmapTestES3, GenerateMipmap1x1Texture)
{ {