Commit afd32d8e by Charlie Lao Committed by Commit Bot

Vulkan: Remove mMaxLevel from ImageHelper class

This CL removes mMaxLevel from ImageHelper class. Instead, it now uses front end's max level information when possible. Bug: b/181800403 Change-Id: Ie0f6bd11e3ca0d4ddfc98f21261396c4d71b7140 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2796153 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarIan Elliott <ianelliott@google.com>
parent 4756d5e6
...@@ -1747,15 +1747,16 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk) ...@@ -1747,15 +1747,16 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk)
// If the image has more levels than supported, generate as many mips as possible at a time. // If the image has more levels than supported, generate as many mips as possible at a time.
const vk::LevelIndex maxGenerateLevels(UtilsVk::GetGenerateMipmapMaxLevels(contextVk)); const vk::LevelIndex maxGenerateLevels(UtilsVk::GetGenerateMipmapMaxLevels(contextVk));
vk::LevelIndex destMaxLevelVk = mImage->toVkLevel(gl::LevelIndex(mState.getMipmapMaxLevel()));
for (vk::LevelIndex destBaseLevelVk = for (vk::LevelIndex destBaseLevelVk =
mImage->toVkLevel(gl::LevelIndex(mState.getEffectiveBaseLevel() + 1)); mImage->toVkLevel(gl::LevelIndex(mState.getEffectiveBaseLevel() + 1));
destBaseLevelVk < vk::LevelIndex(mImage->getLevelCount()); destBaseLevelVk <= destMaxLevelVk;
destBaseLevelVk = destBaseLevelVk + maxGenerateLevels.get()) destBaseLevelVk = destBaseLevelVk + maxGenerateLevels.get())
{ {
vk::CommandBufferAccess access; vk::CommandBufferAccess access;
uint32_t writeLevelCount = uint32_t writeLevelCount =
std::min(maxGenerateLevels.get(), mImage->getLevelCount() - destBaseLevelVk.get()); std::min(maxGenerateLevels.get(), destMaxLevelVk.get() + 1 - destBaseLevelVk.get());
access.onImageComputeShaderWrite(mImage->toGLLevel(destBaseLevelVk), writeLevelCount, 0, access.onImageComputeShaderWrite(mImage->toGLLevel(destBaseLevelVk), writeLevelCount, 0,
mImage->getLayerCount(), VK_IMAGE_ASPECT_COLOR_BIT, mImage->getLayerCount(), VK_IMAGE_ASPECT_COLOR_BIT,
mImage); mImage);
...@@ -1781,7 +1782,7 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk) ...@@ -1781,7 +1782,7 @@ angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk)
vk::LevelIndex destLevelVk = destBaseLevelVk + levelVk.get(); vk::LevelIndex destLevelVk = destBaseLevelVk + levelVk.get();
// If fewer levels left than maxGenerateLevels, cut the loop short. // If fewer levels left than maxGenerateLevels, cut the loop short.
if (destLevelVk >= vk::LevelIndex(mImage->getLevelCount())) if (destLevelVk > destMaxLevelVk)
{ {
destLevelCount = levelVk; destLevelCount = levelVk;
break; break;
...@@ -1925,7 +1926,6 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk, ...@@ -1925,7 +1926,6 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
{ {
mImage->setFirstAllocatedLevel(baseLevel); mImage->setFirstAllocatedLevel(baseLevel);
} }
mImage->setMaxLevel(maxLevel);
// No further work to do, let staged updates handle the new levels // No further work to do, let staged updates handle the new levels
return angle::Result::Continue; return angle::Result::Continue;
...@@ -1939,7 +1939,7 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk, ...@@ -1939,7 +1939,7 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
ASSERT(!baseLevelChanged || baseLevel >= mImage->getFirstAllocatedLevel()); ASSERT(!baseLevelChanged || baseLevel >= mImage->getFirstAllocatedLevel());
ASSERT(!maxLevelChanged || maxLevel < gl::LevelIndex(mImage->getLevelCount())); ASSERT(!maxLevelChanged || maxLevel < gl::LevelIndex(mImage->getLevelCount()));
} }
else if (!baseLevelChanged && (maxLevel < baseLevel + mImage->getLevelCount())) else if (!baseLevelChanged && (maxLevel <= mImage->getLastAllocatedLevel()))
{ {
// With a valid image, check if only changing the maxLevel to a subset of the texture's // With a valid image, check if only changing the maxLevel to a subset of the texture's
// actual number of mip levels // actual number of mip levels
...@@ -1955,9 +1955,6 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk, ...@@ -1955,9 +1955,6 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
// Don't need to respecify the texture; but do need to update which vkImageView's are // Don't need to respecify the texture; but do need to update which vkImageView's are
// served up by ImageViewHelper // served up by ImageViewHelper
// Track the levels in our ImageHelper
mImage->setMaxLevel(maxLevel);
// Update the current max level in ImageViewHelper // Update the current max level in ImageViewHelper
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc(); const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
// We use a special layer count here to handle EGLImages. They might only be // We use a special layer count here to handle EGLImages. They might only be
...@@ -2026,7 +2023,7 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk, ...@@ -2026,7 +2023,7 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
{ {
ASSERT((mImage->getFirstAllocatedLevel() == gl::LevelIndex(0)) || ASSERT((mImage->getFirstAllocatedLevel() == gl::LevelIndex(0)) ||
(mImage->getFirstAllocatedLevel() == baseLevel)); (mImage->getFirstAllocatedLevel() == baseLevel));
ASSERT((mImage->getMaxLevel() == gl::LevelIndex(0)) || (mImage->getMaxLevel() == maxLevel)); ASSERT(!mState.getImmutableFormat());
releaseImage(contextVk); releaseImage(contextVk);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -2074,10 +2071,6 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk, ...@@ -2074,10 +2071,6 @@ angle::Result TextureVk::respecifyImageStorageAndLevels(ContextVk *contextVk,
dstImage = mImage; dstImage = mImage;
} }
// After flushing prior staged updates, track the new levels (they are used in the flush, hence
// the wait)
dstImage->setMaxLevel(maxLevel);
// Transfer the entire contents of the source image into the destination image. // Transfer the entire contents of the source image into the destination image.
ANGLE_TRY(copyAndStageImageData(contextVk, previousFirstAllocateLevel, srcImage, dstImage)); ANGLE_TRY(copyAndStageImageData(contextVk, previousFirstAllocateLevel, srcImage, dstImage));
......
...@@ -3636,7 +3636,6 @@ ImageHelper::ImageHelper(ImageHelper &&other) ...@@ -3636,7 +3636,6 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mYuvConversionSampler(std::move(other.mYuvConversionSampler)), mYuvConversionSampler(std::move(other.mYuvConversionSampler)),
mExternalFormat(other.mExternalFormat), mExternalFormat(other.mExternalFormat),
mFirstAllocatedLevel(other.mFirstAllocatedLevel), mFirstAllocatedLevel(other.mFirstAllocatedLevel),
mMaxLevel(other.mMaxLevel),
mLayerCount(other.mLayerCount), mLayerCount(other.mLayerCount),
mLevelCount(other.mLevelCount), mLevelCount(other.mLevelCount),
mStagingBuffer(std::move(other.mStagingBuffer)), mStagingBuffer(std::move(other.mStagingBuffer)),
...@@ -3670,7 +3669,6 @@ void ImageHelper::resetCachedProperties() ...@@ -3670,7 +3669,6 @@ void ImageHelper::resetCachedProperties()
mLastNonShaderReadOnlyLayout = ImageLayout::Undefined; mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
mCurrentShaderReadStageMask = 0; mCurrentShaderReadStageMask = 0;
mFirstAllocatedLevel = gl::LevelIndex(0); mFirstAllocatedLevel = gl::LevelIndex(0);
mMaxLevel = gl::LevelIndex(0);
mLayerCount = 0; mLayerCount = 0;
mLevelCount = 0; mLevelCount = 0;
mExternalFormat = 0; mExternalFormat = 0;
...@@ -3838,7 +3836,6 @@ angle::Result ImageHelper::initExternal(Context *context, ...@@ -3838,7 +3836,6 @@ angle::Result ImageHelper::initExternal(Context *context,
mSamples = std::max(samples, 1); mSamples = std::max(samples, 1);
mImageSerial = context->getRenderer()->getResourceSerialFactory().generateImageSerial(); mImageSerial = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
mFirstAllocatedLevel = immutable ? gl::LevelIndex(0) : baseLevel; mFirstAllocatedLevel = immutable ? gl::LevelIndex(0) : baseLevel;
mMaxLevel = maxLevel;
mLevelCount = mipLevels; mLevelCount = mipLevels;
mLayerCount = layerCount; mLayerCount = layerCount;
mUsage = usage; mUsage = usage;
...@@ -4382,12 +4379,12 @@ angle::Result ImageHelper::initImplicitMultisampledRenderToTexture( ...@@ -4382,12 +4379,12 @@ angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
: VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
constexpr VkImageCreateFlags kMultisampledCreateFlags = 0; constexpr VkImageCreateFlags kMultisampledCreateFlags = 0;
ANGLE_TRY(initExternal(context, textureType, resolveImage.getExtents(), ANGLE_TRY(
resolveImage.getFormat(), samples, kMultisampledUsageFlags, initExternal(context, textureType, resolveImage.getExtents(), resolveImage.getFormat(),
kMultisampledCreateFlags, ImageLayout::Undefined, nullptr, samples, kMultisampledUsageFlags, kMultisampledCreateFlags,
resolveImage.getFirstAllocatedLevel(), resolveImage.getMaxLevel(), ImageLayout::Undefined, nullptr, resolveImage.getFirstAllocatedLevel(),
resolveImage.getLevelCount(), resolveImage.getLayerCount(), resolveImage.getLastAllocatedLevel(), resolveImage.getLevelCount(),
isRobustResourceInitEnabled, false, nullptr)); resolveImage.getLayerCount(), isRobustResourceInitEnabled, false, nullptr));
const VkMemoryPropertyFlags kMultisampledMemoryFlags = const VkMemoryPropertyFlags kMultisampledMemoryFlags =
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
...@@ -4399,7 +4396,7 @@ angle::Result ImageHelper::initImplicitMultisampledRenderToTexture( ...@@ -4399,7 +4396,7 @@ angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
// Remove the emulated format clear from the multisampled image if any. There is one already // Remove the emulated format clear from the multisampled image if any. There is one already
// staged on the resolve image if needed. // staged on the resolve image if needed.
removeStagedUpdates(context, getFirstAllocatedLevel(), getMaxLevel()); removeStagedUpdates(context, getFirstAllocatedLevel(), getLastAllocatedLevel());
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -4571,11 +4568,6 @@ void ImageHelper::setFirstAllocatedLevel(gl::LevelIndex firstLevel) ...@@ -4571,11 +4568,6 @@ void ImageHelper::setFirstAllocatedLevel(gl::LevelIndex firstLevel)
mFirstAllocatedLevel = firstLevel; mFirstAllocatedLevel = firstLevel;
} }
void ImageHelper::setMaxLevel(gl::LevelIndex maxLevel)
{
mMaxLevel = maxLevel;
}
LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
{ {
return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel); return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel);
...@@ -5984,9 +5976,6 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk, ...@@ -5984,9 +5976,6 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
uint32_t updateBaseLayer, updateLayerCount; uint32_t updateBaseLayer, updateLayerCount;
update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount); update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
// If the update level is not within the requested range, skip the update.
const bool isUpdateLevelOutsideRange = updateMipLevelGL > mMaxLevel;
// If the update layers don't intersect the requested layers, skip the update. // If the update layers don't intersect the requested layers, skip the update.
const bool areUpdateLayersOutsideRange = const bool areUpdateLayersOutsideRange =
updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd; updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
...@@ -5997,8 +5986,7 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk, ...@@ -5997,8 +5986,7 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
// them. This can happen when recreating an image that has been partially incompatibly // them. This can happen when recreating an image that has been partially incompatibly
// redefined, in which case only updates to the levels that haven't been redefined // redefined, in which case only updates to the levels that haven't been redefined
// should be flushed. // should be flushed.
if (isUpdateLevelOutsideRange || areUpdateLayersOutsideRange || if (areUpdateLayersOutsideRange || skipLevelsMask.test(updateMipLevelVk.get()))
skipLevelsMask.test(updateMipLevelVk.get()))
{ {
updatesToKeep.emplace_back(std::move(update)); updatesToKeep.emplace_back(std::move(update));
continue; continue;
...@@ -6152,9 +6140,14 @@ bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL, ...@@ -6152,9 +6140,14 @@ bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,
return false; return false;
} }
gl::LevelIndex ImageHelper::getLastAllocatedLevel() const
{
return mFirstAllocatedLevel + mLevelCount - 1;
}
bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
{ {
return hasStagedUpdatesInLevels(mFirstAllocatedLevel, mMaxLevel + 1); return hasStagedUpdatesInLevels(mFirstAllocatedLevel, getLastAllocatedLevel() + 1);
} }
bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
...@@ -6263,17 +6256,16 @@ void ImageHelper::removeSupersededUpdates(ContextVk *contextVk, gl::TexLevelMask ...@@ -6263,17 +6256,16 @@ void ImageHelper::removeSupersededUpdates(ContextVk *contextVk, gl::TexLevelMask
return false; return false;
}; };
for (gl::LevelIndex level = mFirstAllocatedLevel; level <= mMaxLevel; ++level) for (LevelIndex levelVk(0); levelVk < LevelIndex(mLevelCount); ++levelVk)
{ {
std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level); gl::LevelIndex levelGL = toGLLevel(levelVk);
std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
if (levelUpdates == nullptr) if (levelUpdates == nullptr)
{ {
ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size()); ASSERT(static_cast<size_t>(levelGL.get()) >= mSubresourceUpdates.size());
break; break;
} }
LevelIndex levelVk = toVkLevel(level);
// If level is skipped (because incompatibly redefined), don't remove any of its updates. // If level is skipped (because incompatibly redefined), don't remove any of its updates.
if (skipLevelsMask.test(levelVk.get())) if (skipLevelsMask.test(levelVk.get()))
{ {
......
...@@ -1795,8 +1795,7 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1795,8 +1795,7 @@ class ImageHelper final : public Resource, public angle::Subject
gl::LevelIndex getFirstAllocatedLevel() const { return mFirstAllocatedLevel; } gl::LevelIndex getFirstAllocatedLevel() const { return mFirstAllocatedLevel; }
void setFirstAllocatedLevel(gl::LevelIndex firstLevel); void setFirstAllocatedLevel(gl::LevelIndex firstLevel);
void setMaxLevel(gl::LevelIndex maxLevel); gl::LevelIndex getLastAllocatedLevel() const;
gl::LevelIndex getMaxLevel() const { return mMaxLevel; }
LevelIndex toVkLevel(gl::LevelIndex levelIndexGL) const; LevelIndex toVkLevel(gl::LevelIndex levelIndexGL) const;
gl::LevelIndex toGLLevel(LevelIndex levelIndexVk) const; gl::LevelIndex toGLLevel(LevelIndex levelIndexVk) const;
...@@ -2070,7 +2069,6 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -2070,7 +2069,6 @@ class ImageHelper final : public Resource, public angle::Subject
gl::LevelIndex mFirstAllocatedLevel; gl::LevelIndex mFirstAllocatedLevel;
// Cached properties. // Cached properties.
gl::LevelIndex mMaxLevel;
uint32_t mLayerCount; uint32_t mLayerCount;
uint32_t mLevelCount; uint32_t mLevelCount;
......
...@@ -2708,7 +2708,7 @@ TEST_P(FramebufferTest_ES3, RenderAndInvalidateImmutableTextureWithBellowBaseLev ...@@ -2708,7 +2708,7 @@ TEST_P(FramebufferTest_ES3, RenderAndInvalidateImmutableTextureWithBellowBaseLev
TEST_P(FramebufferTest_ES3, RenderImmutableTextureWithSubImageWithBeyondMaxLevel) TEST_P(FramebufferTest_ES3, RenderImmutableTextureWithSubImageWithBeyondMaxLevel)
{ {
// ToDo: https://issuetracker.google.com/181800403 // ToDo: https://issuetracker.google.com/181800403
ANGLE_SKIP_TEST_IF(IsVulkan() || IsMetal()); ANGLE_SKIP_TEST_IF(IsMetal());
// Set up program to sample from specific lod level. // Set up program to sample from specific lod level.
GLProgram textureLodProgram; GLProgram textureLodProgram;
......
...@@ -3977,6 +3977,59 @@ TEST_P(Texture2DBaseMaxTestES3, RedefineMutableToImmutable) ...@@ -3977,6 +3977,59 @@ TEST_P(Texture2DBaseMaxTestES3, RedefineMutableToImmutable)
} }
} }
// Test that redefine a level with incompatible size beyond the max level.
TEST_P(Texture2DBaseMaxTestES3, RedefineIncompatibleLevelBeyondMaxLevel)
{
initTest(false);
// Test that all mips have the expected data initially (this makes sure the texture image is
// created already).
for (uint32_t lod = 0; lod < kMipCount; ++lod)
{
setLodUniform(lod);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[lod]);
}
uint32_t maxLevel = 1;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxLevel);
// Update level 0
const GLColor kNewMipLevle0Color = GLColor::yellow;
std::array<GLColor, getMipDataSize(kMip0Size, 0)> newMipData;
std::fill(newMipData.begin(), newMipData.end(), kNewMipLevle0Color);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kMip0Size, kMip0Size, GL_RGBA, GL_UNSIGNED_BYTE,
newMipData.data());
// Update level 2 with incompatible data
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE,
newMipData.data());
EXPECT_GL_NO_ERROR();
// Test that the texture looks as expected.
const int w = getWindowWidth() - 1;
const int h = getWindowHeight() - 1;
for (uint32_t lod = 0; lod < maxLevel; ++lod)
{
setLodUniform(lod);
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
if (lod == 0)
{
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipLevle0Color);
EXPECT_PIXEL_COLOR_EQ(w, 0, kNewMipLevle0Color);
EXPECT_PIXEL_COLOR_EQ(0, h, kNewMipLevle0Color);
EXPECT_PIXEL_COLOR_EQ(w, h, kNewMipLevle0Color);
}
else
{
EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[lod]);
EXPECT_PIXEL_COLOR_EQ(w, 0, kMipColors[lod]);
EXPECT_PIXEL_COLOR_EQ(0, h, kMipColors[lod]);
EXPECT_PIXEL_COLOR_EQ(w, h, kMipColors[lod]);
}
}
}
// Test to check that texture completeness is determined correctly when the texture base level is // 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. // greater than 0, and also that level 0 is not sampled when base level is greater than 0.
TEST_P(Texture2DTestES3, DrawWithBaseLevel1) 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