Commit 08b7c55c by Charlie Lao Committed by Commit Bot

Vulkan: Remove mBaseLevel from ImageHelper class

This removes mBaseLevel from ImageHelper class. With the mFirstAllocatedLevel tracking exactly which GL level has been allocated, this cached mBaseLevel is no longer needed. Bug: b/181800403 Change-Id: I99d66c93b0c8f1bd20a5811b51f512a27927201e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2795275 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarIan Elliott <ianelliott@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 41a34d6b
......@@ -1593,10 +1593,7 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context,
}
bool isUpdateToSingleLevelImage =
mImage->getLevelCount() == 1 && mImage->getBaseLevel() == levelIndexGL;
// If it is single level image, baseLevel must equal to firstAllocateLevel
ASSERT(!isUpdateToSingleLevelImage ||
mImage->getFirstAllocatedLevel() == mImage->getBaseLevel());
mImage->getLevelCount() == 1 && mImage->getFirstAllocatedLevel() == levelIndexGL;
// If incompatible, and redefining the single-level image, release it so it can be
// recreated immediately. This is an optimization to avoid an extra copy.
......@@ -1864,11 +1861,13 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
ASSERT(mImage->valid());
// If base level has changed, the front-end should have called syncState already.
ASSERT(mImage->getBaseLevel() == gl::LevelIndex(mState.getEffectiveBaseLevel()));
ASSERT(mState.getImmutableFormat() ||
mImage->getFirstAllocatedLevel() == gl::LevelIndex(mState.getEffectiveBaseLevel()));
// Only staged update here is the robust resource init if any.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
vk::LevelIndex baseLevel = mImage->toVkLevel(gl::LevelIndex(mState.getEffectiveBaseLevel()));
vk::LevelIndex maxLevel = mImage->toVkLevel(gl::LevelIndex(mState.getMipmapMaxLevel()));
ASSERT(maxLevel != vk::LevelIndex(0));
......@@ -1888,7 +1887,7 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
kBlitFeatureFlags))
{
// Otherwise, use blit if possible.
return mImage->generateMipmapsWithBlit(contextVk, maxLevel);
return mImage->generateMipmapsWithBlit(contextVk, baseLevel, maxLevel);
}
ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_HIGH,
......@@ -1904,33 +1903,29 @@ angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLev
}
angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
gl::LevelIndex baseLevel,
gl::LevelIndex maxLevel)
bool baseLevelChanged,
bool maxLevelChanged)
{
if (!mImage)
{
return angle::Result::Continue;
}
// Track the previous levels for use in update loop below
gl::LevelIndex previousBaseLevel = mImage->getBaseLevel();
gl::LevelIndex previousMaxLevel = mImage->getMaxLevel();
// Caller already checked this. Shouldn't reach here if none of them are changed.
ASSERT(baseLevelChanged || maxLevelChanged);
gl::LevelIndex baseLevel(mState.getEffectiveBaseLevel());
gl::LevelIndex maxLevel(mState.getEffectiveMaxLevel());
ASSERT(baseLevel <= maxLevel);
bool baseLevelChanged = baseLevel != previousBaseLevel;
bool maxLevelChanged = previousMaxLevel != maxLevel;
if (!(baseLevelChanged || maxLevelChanged))
{
// This scenario is a noop, most likely maxLevel has been lowered to a level that already
// reflects the current state of the image
return angle::Result::Continue;
}
if (!mImage->valid())
{
// Track the levels in our ImageHelper
mImage->setBaseAndMaxLevels(baseLevel, maxLevel);
if (!mState.getImmutableFormat())
{
mImage->setFirstAllocatedLevel(baseLevel);
}
mImage->setMaxLevel(maxLevel);
// No further work to do, let staged updates handle the new levels
return angle::Result::Continue;
......@@ -1959,8 +1954,9 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
{
// Don't need to respecify the texture; but do need to update which vkImageView's are
// served up by ImageViewHelper
// Track the levels in our ImageHelper
mImage->setBaseAndMaxLevels(baseLevel, maxLevel);
mImage->setMaxLevel(maxLevel);
// Update the current max level in ImageViewHelper
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
......@@ -1972,7 +1968,8 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
maxLevel - baseLevel + 1, layerCount);
}
return respecifyImageStorageAndLevels(contextVk, previousBaseLevel, baseLevel, maxLevel);
return respecifyImageStorageAndLevels(contextVk, mImage->getFirstAllocatedLevel(), baseLevel,
maxLevel);
}
angle::Result TextureVk::copyAndStageImageData(ContextVk *contextVk,
......@@ -2027,8 +2024,8 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
{
if (!mImage->valid())
{
ASSERT((mImage->getBaseLevel() == gl::LevelIndex(0)) ||
(mImage->getBaseLevel() == baseLevel));
ASSERT((mImage->getFirstAllocatedLevel() == gl::LevelIndex(0)) ||
(mImage->getFirstAllocatedLevel() == baseLevel));
ASSERT((mImage->getMaxLevel() == gl::LevelIndex(0)) || (mImage->getMaxLevel() == maxLevel));
releaseImage(contextVk);
return angle::Result::Continue;
......@@ -2079,7 +2076,7 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
// After flushing prior staged updates, track the new levels (they are used in the flush, hence
// the wait)
dstImage->setBaseAndMaxLevels(baseLevel, maxLevel);
dstImage->setMaxLevel(maxLevel);
// Transfer the entire contents of the source image into the destination image.
ANGLE_TRY(copyAndStageImageData(contextVk, previousFirstAllocateLevel, srcImage, dstImage));
......@@ -2090,6 +2087,11 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
if (ownsCurrentImage)
{
releaseImage(contextVk);
if (!mState.getImmutableFormat())
{
dstImage->setFirstAllocatedLevel(baseLevel);
}
}
mImage->retain(&contextVk->getResourceUseList());
......@@ -2334,14 +2336,14 @@ void TextureVk::prepareForGenerateMipmap(ContextVk *contextVk)
"levels mask assumes 32-bits is enough");
gl::TexLevelMask::value_type levelsMask = angle::Bit<uint32_t>(maxLevel + 1 - baseLevel) - 1;
gl::LevelIndex imageBaseLevel = mImage->getBaseLevel();
if (imageBaseLevel > baseLevel)
gl::LevelIndex imageAllocatedLevel = mImage->getFirstAllocatedLevel();
if (imageAllocatedLevel > baseLevel)
{
levelsMask >>= imageBaseLevel - baseLevel;
levelsMask >>= imageAllocatedLevel - baseLevel;
}
else
{
levelsMask <<= baseLevel - imageBaseLevel;
levelsMask <<= baseLevel - imageAllocatedLevel;
}
mRedefinedLevels &= gl::TexLevelMask(~levelsMask);
......@@ -2434,11 +2436,11 @@ angle::Result TextureVk::syncState(const gl::Context *context,
}
// Set base and max level before initializing the image
if (dirtyBits.test(gl::Texture::DIRTY_BIT_MAX_LEVEL) ||
dirtyBits.test(gl::Texture::DIRTY_BIT_BASE_LEVEL))
bool baseLevelChanged = dirtyBits.test(gl::Texture::DIRTY_BIT_BASE_LEVEL);
bool maxLevelChanged = dirtyBits.test(gl::Texture::DIRTY_BIT_MAX_LEVEL);
if (maxLevelChanged || baseLevelChanged)
{
ANGLE_TRY(updateBaseMaxLevels(contextVk, gl::LevelIndex(mState.getEffectiveBaseLevel()),
gl::LevelIndex(mState.getEffectiveMaxLevel())));
ANGLE_TRY(updateBaseMaxLevels(contextVk, baseLevelChanged, maxLevelChanged));
// Updating levels could have respecified the storage, recapture mImageCreateFlags
oldCreateFlags = mImageCreateFlags;
......@@ -2788,7 +2790,8 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk,
{
ASSERT(mImage != nullptr && mImage->valid());
gl::LevelIndex baseLevelGL = getNativeImageLevel(mImage->getBaseLevel());
gl::LevelIndex baseLevelGL =
getNativeImageLevel(gl::LevelIndex(mState.getEffectiveBaseLevel()));
vk::LevelIndex baseLevelVk = mImage->toVkLevel(baseLevelGL);
uint32_t baseLayer = getNativeImageLayer(0);
......
......@@ -450,8 +450,8 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// Update base and max levels, and re-create image if needed.
angle::Result updateBaseMaxLevels(ContextVk *contextVk,
gl::LevelIndex baseLevelGL,
gl::LevelIndex maxLevelGL);
bool baseLevelChanged,
bool maxLevelChanged);
bool isFastUnpackPossible(const vk::Format &vkFormat, size_t offset) const;
......
......@@ -3272,7 +3272,7 @@ angle::Result UtilsVk::cullOverlayWidgets(ContextVk *contextVk,
&descriptorSet));
ASSERT(dest->getLevelCount() == 1 && dest->getLayerCount() == 1 &&
dest->getBaseLevel() == gl::LevelIndex(0));
dest->getFirstAllocatedLevel() == gl::LevelIndex(0));
vk::CommandBufferAccess access;
access.onBufferComputeShaderRead(enabledWidgetsBuffer);
......@@ -3349,7 +3349,7 @@ angle::Result UtilsVk::drawOverlay(ContextVk *contextVk,
&descriptorSet));
ASSERT(dest->getLevelCount() == 1 && dest->getLayerCount() == 1 &&
dest->getBaseLevel() == gl::LevelIndex(0));
dest->getFirstAllocatedLevel() == gl::LevelIndex(0));
vk::CommandBufferAccess access;
access.onImageComputeShaderWrite(gl::LevelIndex(0), 1, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT, dest);
......
......@@ -3636,7 +3636,6 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mYuvConversionSampler(std::move(other.mYuvConversionSampler)),
mExternalFormat(other.mExternalFormat),
mFirstAllocatedLevel(other.mFirstAllocatedLevel),
mBaseLevel(other.mBaseLevel),
mMaxLevel(other.mMaxLevel),
mLayerCount(other.mLayerCount),
mLevelCount(other.mLevelCount),
......@@ -3671,7 +3670,6 @@ void ImageHelper::resetCachedProperties()
mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
mCurrentShaderReadStageMask = 0;
mFirstAllocatedLevel = gl::LevelIndex(0);
mBaseLevel = gl::LevelIndex(0);
mMaxLevel = gl::LevelIndex(0);
mLayerCount = 0;
mLevelCount = 0;
......@@ -3840,7 +3838,6 @@ angle::Result ImageHelper::initExternal(Context *context,
mSamples = std::max(samples, 1);
mImageSerial = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
mFirstAllocatedLevel = immutable ? gl::LevelIndex(0) : baseLevel;
mBaseLevel = baseLevel;
mMaxLevel = maxLevel;
mLevelCount = mipLevels;
mLayerCount = layerCount;
......@@ -4565,17 +4562,18 @@ bool ImageHelper::isReleasedToExternal() const
#endif
}
void ImageHelper::setBaseAndMaxLevels(gl::LevelIndex baseLevel, gl::LevelIndex maxLevel)
void ImageHelper::setFirstAllocatedLevel(gl::LevelIndex firstLevel)
{
mBaseLevel = baseLevel;
mMaxLevel = maxLevel;
// For immutable texture, we always allocate the entire mipmap chain [0, mLevelCount-1].
// For mutable textures, we will try to reallocate based on baseLevel change
if (!mImmutable)
{
mFirstAllocatedLevel = baseLevel;
}
ASSERT(!mImmutable);
ASSERT(!valid());
mFirstAllocatedLevel = firstLevel;
}
void ImageHelper::setMaxLevel(gl::LevelIndex maxLevel)
{
mMaxLevel = maxLevel;
}
LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
......@@ -4943,10 +4941,13 @@ angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, LevelIndex maxLevel)
angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk,
LevelIndex baseLevel,
LevelIndex maxLevel)
{
CommandBufferAccess access;
access.onImageTransferWrite(mBaseLevel + 1, maxLevel.get(), 0, mLayerCount,
gl::LevelIndex baseLevelGL = toGLLevel(baseLevel);
access.onImageTransferWrite(baseLevelGL + 1, maxLevel.get(), 0, mLayerCount,
VK_IMAGE_ASPECT_COLOR_BIT, this);
CommandBuffer *commandBuffer;
......@@ -4970,7 +4971,6 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, LevelIn
barrier.subresourceRange.levelCount = 1;
const VkFilter filter = gl_vk::GetFilter(CalculateGenerateMipmapFilter(contextVk, getFormat()));
LevelIndex baseLevelVk = toVkLevel(mBaseLevel);
for (LevelIndex mipLevel(1); mipLevel <= LevelIndex(mLevelCount); ++mipLevel)
{
......@@ -4978,7 +4978,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, LevelIn
int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
int32_t nextMipDepth = std::max<int32_t>(1, mipDepth >> 1);
if (mipLevel > baseLevelVk && mipLevel <= maxLevel)
if (mipLevel > baseLevel && mipLevel <= maxLevel)
{
barrier.subresourceRange.baseMipLevel = mipLevel.get() - 1;
barrier.oldLayout = getCurrentLayout();
......
......@@ -1613,7 +1613,9 @@ class ImageHelper final : public Resource, public angle::Subject
GLsizei srcDepth);
// Generate mipmap from level 0 into the rest of the levels with blit.
angle::Result generateMipmapsWithBlit(ContextVk *contextVk, LevelIndex maxLevel);
angle::Result generateMipmapsWithBlit(ContextVk *contextVk,
LevelIndex baseLevel,
LevelIndex maxLevel);
// Resolve this image into a destination image. This image should be in the TransferSrc layout.
// The destination image is automatically transitioned into TransferDst.
......@@ -1792,8 +1794,8 @@ class ImageHelper final : public Resource, public angle::Subject
bool isReleasedToExternal() const;
gl::LevelIndex getFirstAllocatedLevel() const { return mFirstAllocatedLevel; }
gl::LevelIndex getBaseLevel() const { return mBaseLevel; }
void setBaseAndMaxLevels(gl::LevelIndex baseLevel, gl::LevelIndex maxLevel);
void setFirstAllocatedLevel(gl::LevelIndex firstLevel);
void setMaxLevel(gl::LevelIndex maxLevel);
gl::LevelIndex getMaxLevel() const { return mMaxLevel; }
LevelIndex toVkLevel(gl::LevelIndex levelIndexGL) const;
gl::LevelIndex toGLLevel(LevelIndex levelIndexVk) const;
......@@ -2068,7 +2070,6 @@ class ImageHelper final : public Resource, public angle::Subject
gl::LevelIndex mFirstAllocatedLevel;
// Cached properties.
gl::LevelIndex mBaseLevel;
gl::LevelIndex mMaxLevel;
uint32_t mLayerCount;
uint32_t mLevelCount;
......
......@@ -3922,6 +3922,61 @@ TEST_P(Texture2DBaseMaxTestES3, StageInvalidLevels)
}
}
// Test redefine a mutable texture into an immutable texture.
TEST_P(Texture2DBaseMaxTestES3, RedefineMutableToImmutable)
{
// http://anglebug.com/4710
ANGLE_SKIP_TEST_IF(IsD3D());
// http://anglebug.com/4701
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsOSX());
constexpr uint32_t kBaseLevel = 1;
const GLColor kNewMipColors[kMipCount] = {
GLColor::yellow,
GLColor::cyan,
GLColor::white,
GLColor(127u, 127u, 127u, 255u),
};
initTest(false);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, kBaseLevel);
// Test that all mips have the expected data
for (uint32_t lod = kBaseLevel; lod < kMipCount; ++lod)
{
setLodUniform(lod - kBaseLevel);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[lod]);
}
glTexStorage2D(GL_TEXTURE_2D, kMipCount, GL_RGBA8, kMip0Size, kMip0Size);
std::array<GLColor, getTotalMipDataSize(kMip0Size)> mipData;
fillMipData(mipData.data(), kMip0Size, kNewMipColors);
for (size_t mip = 0; mip < kMipCount; ++mip)
{
glTexSubImage2D(GL_TEXTURE_2D, mip, 0, 0, kMip0Size >> mip, kMip0Size >> mip, GL_RGBA,
GL_UNSIGNED_BYTE, mipData.data() + getMipDataOffset(kMip0Size, mip));
}
// Test that all enabled mips have the expected data
for (uint32_t lod = kBaseLevel; lod < kMipCount; ++lod)
{
setLodUniform(lod - kBaseLevel);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[lod]);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
for (uint32_t lod = 0; lod < kBaseLevel; ++lod)
{
setLodUniform(lod);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[lod]);
}
}
// Test to check that texture completeness is determined correctly when the texture base level is
// greater than 0, and also that level 0 is not sampled when base level is greater than 0.
TEST_P(Texture2DTestES3, DrawWithBaseLevel1)
......
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