Commit 25b0de6b by Jamie Madill Committed by Commit Bot

Vulkan: Squash Texture+ImageView Serial and improve caching.

Previously we regenerated TextureSerial on Texture state changes such as base/max level changes. This caused ANGLE to update descriptor sets even though it was using the same image view handles. This change instead uses an ImageViewSubresourceSerial which includes both a serial for the ImageView and a 32-bit packed subresource range. The CL speeds up NBA2k because ANGLE no longer writes new descriptors for Texture max level changes. Local testing showed up to a 40% speedup. Also adds a regression test with a counter for the number of descriptor set writes in a frame. This change will also be useful in upcoming changes that track Image serials in the RenderPass. Bug: angleproject:4911 Change-Id: I66249634aa56288079acf2c0eb8aa3391103533c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2333396 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 6aed2832
...@@ -3875,8 +3875,9 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context) ...@@ -3875,8 +3875,9 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
mActiveTextures[textureUnit].texture = textureVk; mActiveTextures[textureUnit].texture = textureVk;
mActiveTextures[textureUnit].sampler = &samplerVk; mActiveTextures[textureUnit].sampler = &samplerVk;
mActiveTexturesDesc.update(textureUnit, textureVk->getSerial(),
samplerVk.getSamplerSerial()); vk::ImageViewSubresourceSerial imageViewSerial = textureVk->getImageViewSubresourceSerial();
mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerVk.getSamplerSerial());
if (textureVk->getImage().hasImmutableSampler()) if (textureVk->getImage().hasImmutableSampler())
{ {
......
...@@ -77,7 +77,7 @@ vk::ImageViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl( ...@@ -77,7 +77,7 @@ vk::ImageViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
ASSERT(mLevelIndexGL < std::numeric_limits<uint16_t>::max()); ASSERT(mLevelIndexGL < std::numeric_limits<uint16_t>::max());
vk::ImageViewSubresourceSerial imageViewSerial = vk::ImageViewSubresourceSerial imageViewSerial =
imageViews->getSubresourceSerial(mLevelIndexGL, mLayerIndex); imageViews->getSubresourceSerial(mLevelIndexGL, 1, mLayerIndex, vk::LayerMode::Single);
return imageViewSerial; return imageViewSerial;
} }
......
...@@ -1249,7 +1249,6 @@ void TextureVk::setImageHelper(ContextVk *contextVk, ...@@ -1249,7 +1249,6 @@ void TextureVk::setImageHelper(ContextVk *contextVk,
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
updateSerial(contextVk);
mImageViews.init(renderer); mImageViews.init(renderer);
} }
...@@ -1699,8 +1698,6 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk, ...@@ -1699,8 +1698,6 @@ angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
// Track the levels in our ImageHelper // Track the levels in our ImageHelper
mImage->setBaseAndMaxLevels(baseLevel, maxLevel); mImage->setBaseAndMaxLevels(baseLevel, maxLevel);
updateSerial(contextVk);
// 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
...@@ -2162,8 +2159,6 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -2162,8 +2159,6 @@ angle::Result TextureVk::syncState(const gl::Context *context,
mImage->getExternalFormat()); mImage->getExternalFormat());
ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, samplerDesc, &mSampler)); ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, samplerDesc, &mSampler));
updateSerial(contextVk);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -2301,8 +2296,6 @@ angle::Result TextureVk::initImage(ContextVk *contextVk, ...@@ -2301,8 +2296,6 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
ANGLE_TRY(initImageViews(contextVk, format, sized, levelCount, layerCount)); ANGLE_TRY(initImageViews(contextVk, format, sized, levelCount, layerCount));
updateSerial(contextVk);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -2522,9 +2515,11 @@ void TextureVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMe ...@@ -2522,9 +2515,11 @@ void TextureVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMe
onStateChange(angle::SubjectMessage::SubjectChanged); onStateChange(angle::SubjectMessage::SubjectChanged);
} }
void TextureVk::updateSerial(ContextVk *contextVk) vk::ImageViewSubresourceSerial TextureVk::getImageViewSubresourceSerial() const
{ {
vk::ResourceSerialFactory &factory = contextVk->getRenderer()->getResourceSerialFactory(); uint32_t baseLevel = mState.getEffectiveBaseLevel();
mSerial = factory.generateTextureSerial(); // getMipmapMaxLevel will clamp to the max level if it is smaller than the number of mips.
uint32_t levelCount = mState.getMipmapMaxLevel() - baseLevel + 1;
return mImageViews.getSubresourceSerial(baseLevel, levelCount, 0, vk::LayerMode::All);
} }
} // namespace rx } // namespace rx
...@@ -191,7 +191,7 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -191,7 +191,7 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// Normally, initialize the image with enabled mipmap level counts. // Normally, initialize the image with enabled mipmap level counts.
angle::Result ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels); angle::Result ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels);
vk::TextureSerial getSerial() const { return mSerial; } vk::ImageViewSubresourceSerial getImageViewSubresourceSerial() const;
void overrideStagingBufferSizeForTesting(size_t initialSizeForTesting) void overrideStagingBufferSizeForTesting(size_t initialSizeForTesting)
{ {
...@@ -397,8 +397,6 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -397,8 +397,6 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
return (mImage->valid()) ? mImage->getTilingMode() : VK_IMAGE_TILING_OPTIMAL; return (mImage->valid()) ? mImage->getTilingMode() : VK_IMAGE_TILING_OPTIMAL;
} }
void updateSerial(ContextVk *contextVk);
bool mOwnsImage; bool mOwnsImage;
bool mRequiresSRGBViews; bool mRequiresSRGBViews;
...@@ -435,9 +433,6 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -435,9 +433,6 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// Level is first dimension, layer is second // Level is first dimension, layer is second
std::vector<RenderTargetVector> mRenderTargets; std::vector<RenderTargetVector> mRenderTargets;
// The unique object id is used for cache indexing.
vk::TextureSerial mSerial;
// Overridden in some tests. // Overridden in some tests.
size_t mStagingBufferInitialSize; size_t mStagingBufferInitialSize;
......
...@@ -1711,7 +1711,7 @@ void PipelineHelper::addTransition(GraphicsPipelineTransitionBits bits, ...@@ -1711,7 +1711,7 @@ void PipelineHelper::addTransition(GraphicsPipelineTransitionBits bits,
TextureDescriptorDesc::TextureDescriptorDesc() : mMaxIndex(0) TextureDescriptorDesc::TextureDescriptorDesc() : mMaxIndex(0)
{ {
mSerials.fill({0, 0}); mSerials.fill({kInvalidImageViewSubresourceSerial, kInvalidSamplerSerial});
} }
TextureDescriptorDesc::~TextureDescriptorDesc() = default; TextureDescriptorDesc::~TextureDescriptorDesc() = default;
...@@ -1720,7 +1720,7 @@ TextureDescriptorDesc &TextureDescriptorDesc::operator=(const TextureDescriptorD ...@@ -1720,7 +1720,7 @@ TextureDescriptorDesc &TextureDescriptorDesc::operator=(const TextureDescriptorD
default; default;
void TextureDescriptorDesc::update(size_t index, void TextureDescriptorDesc::update(size_t index,
TextureSerial textureSerial, ImageViewSubresourceSerial imageViewSerial,
SamplerSerial samplerSerial) SamplerSerial samplerSerial)
{ {
if (index >= mMaxIndex) if (index >= mMaxIndex)
...@@ -1728,12 +1728,8 @@ void TextureDescriptorDesc::update(size_t index, ...@@ -1728,12 +1728,8 @@ void TextureDescriptorDesc::update(size_t index,
mMaxIndex = static_cast<uint32_t>(index + 1); mMaxIndex = static_cast<uint32_t>(index + 1);
} }
// If the serial number overflows we should defragment and regenerate all serials. mSerials[index].imageView = imageViewSerial;
// There should never be more than UINT_MAX textures alive at a time. mSerials[index].sampler = samplerSerial;
ASSERT(textureSerial.getValue() < std::numeric_limits<uint32_t>::max());
ASSERT(samplerSerial.getValue() < std::numeric_limits<uint32_t>::max());
mSerials[index].texture = static_cast<uint32_t>(textureSerial.getValue());
mSerials[index].sampler = static_cast<uint32_t>(samplerSerial.getValue());
} }
size_t TextureDescriptorDesc::hash() const size_t TextureDescriptorDesc::hash() const
......
...@@ -789,14 +789,16 @@ ANGLE_INLINE PipelineHelper::PipelineHelper(Pipeline &&pipeline) : mPipeline(std ...@@ -789,14 +789,16 @@ ANGLE_INLINE PipelineHelper::PipelineHelper(Pipeline &&pipeline) : mPipeline(std
struct ImageViewSubresourceSerial struct ImageViewSubresourceSerial
{ {
ImageViewSerial imageViewSerial; ImageViewSerial imageViewSerial;
uint16_t level; uint16_t level : 10; // GL max is 1000 (fits in 10 bits).
uint16_t layer; uint16_t levelCount : 6; // Max 63 levels (2 ** 6 - 1). If we need more, take from layer.
uint16_t layer : 15; // Implementation max is 2048 (11 bits).
uint16_t singleLayer : 1; // true/false only. Not possible to use sub-slices of levels.
}; };
static_assert(sizeof(ImageViewSubresourceSerial) == sizeof(uint64_t), "Size mismatch"); static_assert(sizeof(ImageViewSubresourceSerial) == sizeof(uint64_t), "Size mismatch");
constexpr ImageViewSubresourceSerial kInvalidImageViewSubresourceSerial = {kInvalidImageViewSerial, constexpr ImageViewSubresourceSerial kInvalidImageViewSubresourceSerial = {kInvalidImageViewSerial,
0, 0}; 0, 0, 0, 0};
class TextureDescriptorDesc class TextureDescriptorDesc
{ {
...@@ -807,7 +809,9 @@ class TextureDescriptorDesc ...@@ -807,7 +809,9 @@ class TextureDescriptorDesc
TextureDescriptorDesc(const TextureDescriptorDesc &other); TextureDescriptorDesc(const TextureDescriptorDesc &other);
TextureDescriptorDesc &operator=(const TextureDescriptorDesc &other); TextureDescriptorDesc &operator=(const TextureDescriptorDesc &other);
void update(size_t index, TextureSerial textureSerial, SamplerSerial samplerSerial); void update(size_t index,
ImageViewSubresourceSerial imageViewSerial,
SamplerSerial samplerSerial);
size_t hash() const; size_t hash() const;
void reset(); void reset();
...@@ -818,12 +822,15 @@ class TextureDescriptorDesc ...@@ -818,12 +822,15 @@ class TextureDescriptorDesc
private: private:
uint32_t mMaxIndex; uint32_t mMaxIndex;
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
struct TexUnitSerials struct TexUnitSerials
{ {
uint32_t texture; ImageViewSubresourceSerial imageView;
uint32_t sampler; SamplerSerial sampler;
}; };
gl::ActiveTextureArray<TexUnitSerials> mSerials; gl::ActiveTextureArray<TexUnitSerials> mSerials;
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
}; };
class UniformsAndXfbDesc class UniformsAndXfbDesc
......
...@@ -5331,14 +5331,19 @@ angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk, ...@@ -5331,14 +5331,19 @@ angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk,
imageView, levelVK, 1, layer, 1); imageView, levelVK, 1, layer, 1);
} }
ImageViewSubresourceSerial ImageViewHelper::getSubresourceSerial(uint32_t levelGL, uint32_t layer) ImageViewSubresourceSerial ImageViewHelper::getSubresourceSerial(uint32_t levelGL,
uint32_t levelCount,
uint32_t layer,
LayerMode layerMode) const
{ {
ASSERT(mImageViewSerial.valid()); ASSERT(mImageViewSerial.valid());
ImageViewSubresourceSerial serial; ImageViewSubresourceSerial serial;
serial.imageViewSerial = mImageViewSerial; serial.imageViewSerial = mImageViewSerial;
SetBitField(serial.level, levelGL); SetBitField(serial.level, levelGL);
SetBitField(serial.levelCount, levelCount);
SetBitField(serial.layer, layer); SetBitField(serial.layer, layer);
SetBitField(serial.singleLayer, layerMode == LayerMode::Single ? 1 : 0);
return serial; return serial;
} }
......
...@@ -1588,6 +1588,13 @@ using ImageViewVector = std::vector<ImageView>; ...@@ -1588,6 +1588,13 @@ using ImageViewVector = std::vector<ImageView>;
// A vector of vector of image views. Primary index is layer, secondary index is level. // A vector of vector of image views. Primary index is layer, secondary index is level.
using LayerLevelImageViewVector = std::vector<ImageViewVector>; using LayerLevelImageViewVector = std::vector<ImageViewVector>;
// Address mode for layers: only possible to access either 1 layer or all layers.
enum LayerMode
{
Single,
All
};
class ImageViewHelper : angle::NonCopyable class ImageViewHelper : angle::NonCopyable
{ {
public: public:
...@@ -1717,7 +1724,12 @@ class ImageViewHelper : angle::NonCopyable ...@@ -1717,7 +1724,12 @@ class ImageViewHelper : angle::NonCopyable
const ImageView **imageViewOut); const ImageView **imageViewOut);
// Return unique Serial for an imageView. // Return unique Serial for an imageView.
ImageViewSubresourceSerial getSubresourceSerial(uint32_t levelGL, uint32_t layer); ImageViewSubresourceSerial getSubresourceSerial(uint32_t levelGL,
uint32_t levelCount,
uint32_t layer,
LayerMode layerMode) const;
uint32_t getCurrentMaxLevel() const { return mCurrentMaxLevel; }
private: private:
ImageView &getReadImageView() ImageView &getReadImageView()
......
...@@ -696,8 +696,7 @@ class ClearValuesArray final ...@@ -696,8 +696,7 @@ class ClearValuesArray final
#define ANGLE_VK_SERIAL_OP(X) \ #define ANGLE_VK_SERIAL_OP(X) \
X(Buffer) \ X(Buffer) \
X(ImageView) \ X(ImageView) \
X(Sampler) \ X(Sampler)
X(Texture)
#define ANGLE_DEFINE_VK_SERIAL_TYPE(Type) \ #define ANGLE_DEFINE_VK_SERIAL_TYPE(Type) \
class Type##Serial \ class Type##Serial \
......
...@@ -88,6 +88,58 @@ TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass) ...@@ -88,6 +88,58 @@ TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass)
EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount); EXPECT_EQ(expectedRenderPassCount, actualRenderPassCount);
} }
ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest, ES2_VULKAN(), ES3_VULKAN()); // Tests that changing a Texture's max level hits the descriptor set cache.
TEST_P(VulkanPerformanceCounterTest, ChangingMaxLevelHitsDescriptorCache)
{
rx::ContextVk *contextVk = hackANGLE();
GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow};
// Step 1: Set up a simple mipped 2D Texture rendering loop.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
auto quadVerts = GetQuadVertices();
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, quadVerts.size() * sizeof(quadVerts[0]), quadVerts.data(),
GL_STATIC_DRAW);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
glUseProgram(program);
GLint posLoc = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
ASSERT_NE(-1, posLoc);
glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(posLoc);
ASSERT_GL_NO_ERROR();
glDrawArrays(GL_TRIANGLES, 0, 6);
ASSERT_GL_NO_ERROR();
// Step 2: Change max level and draw.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
ASSERT_GL_NO_ERROR();
uint32_t expectedWriteDescriptorSetCount = contextVk->getWriteDescriptorSetCounter();
// Step 3: Change max level back to original value and verify we hit the cache.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glDrawArrays(GL_TRIANGLES, 0, 6);
ASSERT_GL_NO_ERROR();
uint32_t actualWriteDescriptorSetCount = contextVk->getWriteDescriptorSetCounter();
EXPECT_EQ(expectedWriteDescriptorSetCount, actualWriteDescriptorSetCount);
}
ANGLE_INSTANTIATE_TEST(VulkanPerformanceCounterTest, ES3_VULKAN());
} // anonymous namespace } // anonymous namespace
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