Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit a0d048a

Browse files
ShabbyXCommit Bot
authored andcommitted
Vulkan: Fool-proof usage of GL and VK level indices
Using boxed types, this change allows the compiler to catch errors when a level index in one space (e.g. GL) is mistakenly used in another space (e.g. VK). This change uncovered a number of bugs due to such mistakes which are fixed. Mistakes are still possible when the index is explicitly extracted, for example to be given to a Vulkan command, or when it's created, for example when retrieved from gl::ImageIndex::getLevelIndex. Future work can include using gl::LevelIndex in gl::ImageIndex directly to alleviate the latter at least. Bug: angleproject:4880 Change-Id: I6427c68c3bc096f771402f51c8554d8171758aa9 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2380232 Commit-Queue: Shahbaz Youssefi <[email protected]> Reviewed-by: Tim Van Patten <[email protected]> Reviewed-by: Jamie Madill <[email protected]> Reviewed-by: Charlie Lao <[email protected]>
1 parent 8d412db commit a0d048a

25 files changed

+1193
-443
lines changed

src/libANGLE/angletypes.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,63 @@ using TextureBarrierVector = BarrierVector<TextureAndLayout>;
815815
// necessary. Returns 0 if no buffer is bound or if integer overflow occurs.
816816
GLsizeiptr GetBoundBufferAvailableSize(const OffsetBindingPointer<Buffer> &binding);
817817

818+
// A texture level index.
819+
template <typename T>
820+
class LevelIndexWrapper
821+
{
822+
public:
823+
LevelIndexWrapper() = default;
824+
explicit constexpr LevelIndexWrapper(T levelIndex) : mLevelIndex(levelIndex) {}
825+
constexpr LevelIndexWrapper(const LevelIndexWrapper &other) = default;
826+
constexpr LevelIndexWrapper &operator=(const LevelIndexWrapper &other) = default;
827+
828+
constexpr T get() const { return mLevelIndex; }
829+
830+
LevelIndexWrapper &operator++()
831+
{
832+
++mLevelIndex;
833+
return *this;
834+
}
835+
constexpr bool operator<(const LevelIndexWrapper &other) const
836+
{
837+
return mLevelIndex < other.mLevelIndex;
838+
}
839+
constexpr bool operator<=(const LevelIndexWrapper &other) const
840+
{
841+
return mLevelIndex <= other.mLevelIndex;
842+
}
843+
constexpr bool operator>(const LevelIndexWrapper &other) const
844+
{
845+
return mLevelIndex > other.mLevelIndex;
846+
}
847+
constexpr bool operator>=(const LevelIndexWrapper &other) const
848+
{
849+
return mLevelIndex >= other.mLevelIndex;
850+
}
851+
constexpr bool operator==(const LevelIndexWrapper &other) const
852+
{
853+
return mLevelIndex == other.mLevelIndex;
854+
}
855+
constexpr bool operator!=(const LevelIndexWrapper &other) const
856+
{
857+
return mLevelIndex != other.mLevelIndex;
858+
}
859+
constexpr LevelIndexWrapper operator+(T other) const
860+
{
861+
return LevelIndexWrapper(mLevelIndex + other);
862+
}
863+
constexpr LevelIndexWrapper operator-(T other) const
864+
{
865+
return LevelIndexWrapper(mLevelIndex - other);
866+
}
867+
constexpr T operator-(LevelIndexWrapper other) const { return mLevelIndex - other.mLevelIndex; }
868+
869+
private:
870+
T mLevelIndex;
871+
};
872+
873+
// A GL texture level index.
874+
using LevelIndex = LevelIndexWrapper<GLint>;
818875
} // namespace gl
819876

820877
namespace rx

src/libANGLE/renderer/vulkan/FramebufferVk.cpp

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -779,15 +779,15 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
779779
ANGLE_TRY(contextVk->onImageTransferWrite(imageAspectMask, dstImage));
780780
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
781781

782-
VkImageBlit blit = {};
783-
blit.srcSubresource.aspectMask = blitAspectMask;
784-
blit.srcSubresource.mipLevel = readRenderTarget->getLevelIndex();
782+
VkImageBlit blit = {};
783+
blit.srcSubresource.aspectMask = blitAspectMask;
784+
blit.srcSubresource.mipLevel = srcImage->toVKLevel(readRenderTarget->getLevelIndex()).get();
785785
blit.srcSubresource.baseArrayLayer = readRenderTarget->getLayerIndex();
786786
blit.srcSubresource.layerCount = 1;
787787
blit.srcOffsets[0] = {sourceArea.x0(), sourceArea.y0(), 0};
788788
blit.srcOffsets[1] = {sourceArea.x1(), sourceArea.y1(), 1};
789789
blit.dstSubresource.aspectMask = blitAspectMask;
790-
blit.dstSubresource.mipLevel = drawRenderTarget->getLevelIndex();
790+
blit.dstSubresource.mipLevel = dstImage->toVKLevel(drawRenderTarget->getLevelIndex()).get();
791791
blit.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
792792
blit.dstSubresource.layerCount = 1;
793793
blit.dstOffsets[0] = {destArea.x0(), destArea.y0(), 0};
@@ -1028,7 +1028,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
10281028
params.srcLayer = readRenderTarget->getLayerIndex();
10291029

10301030
// Multisampled images are not allowed to have mips.
1031-
ASSERT(!isColorResolve || readRenderTarget->getLevelIndex() == 0);
1031+
ASSERT(!isColorResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0));
10321032

10331033
// If there was no clipping and the format capabilities allow us, use Vulkan's builtin blit.
10341034
// The reason clipping is prohibited in this path is that due to rounding errors, it would
@@ -1127,7 +1127,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
11271127
params.srcLayer = readRenderTarget->getLayerIndex();
11281128

11291129
// Multisampled images are not allowed to have mips.
1130-
ASSERT(!isDepthStencilResolve || readRenderTarget->getLevelIndex() == 0);
1130+
ASSERT(!isDepthStencilResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0));
11311131

11321132
// Similarly, only blit if there's been no clipping or rotating.
11331133
bool canBlitWithCommand = !isDepthStencilResolve && noClip &&
@@ -1158,8 +1158,9 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
11581158
vk::DeviceScoped<vk::ImageView> stencilView(contextVk->getDevice());
11591159

11601160
vk::ImageHelper *depthStencilImage = &readRenderTarget->getImageForCopy();
1161-
uint32_t levelIndex = readRenderTarget->getLevelIndex();
1162-
uint32_t layerIndex = readRenderTarget->getLayerIndex();
1161+
vk::LevelIndex levelIndex =
1162+
depthStencilImage->toVKLevel(readRenderTarget->getLevelIndex());
1163+
uint32_t layerIndex = readRenderTarget->getLayerIndex();
11631164
gl::TextureType textureType = vk::Get2DTextureType(depthStencilImage->getLayerCount(),
11641165
depthStencilImage->getSamples());
11651166

@@ -1302,8 +1303,8 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
13021303
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
13031304

13041305
vk::ImageHelper &dstImage = drawRenderTarget->getImageForWrite();
1305-
uint32_t levelVK = drawRenderTarget->getLevelIndex() - dstImage.getBaseLevel();
1306-
resolveRegion.dstSubresource.mipLevel = levelVK;
1306+
vk::LevelIndex levelVK = dstImage.toVKLevel(drawRenderTarget->getLevelIndex());
1307+
resolveRegion.dstSubresource.mipLevel = levelVK.get();
13071308
resolveRegion.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
13081309

13091310
srcImage->resolve(&dstImage, resolveRegion, &commandBuffer);
@@ -1331,9 +1332,9 @@ angle::Result FramebufferVk::copyResolveToMultisampedAttachment(ContextVk *conte
13311332
// Note: neither vkCmdCopyImage nor vkCmdBlitImage allow the destination to be multisampled.
13321333
// There's no choice but to use a draw-based path to perform this copy.
13331334

1334-
gl::Extents extents = colorRenderTarget->getExtents();
1335-
uint32_t levelVK = colorRenderTarget->getLevelIndex() - src->getBaseLevel();
1336-
uint32_t layer = colorRenderTarget->getLayerIndex();
1335+
gl::Extents extents = colorRenderTarget->getExtents();
1336+
vk::LevelIndex levelVK = src->toVKLevel(colorRenderTarget->getLevelIndex());
1337+
uint32_t layer = colorRenderTarget->getLayerIndex();
13371338

13381339
UtilsVk::CopyImageParameters params;
13391340
params.srcOffset[0] = 0;
@@ -1342,7 +1343,7 @@ angle::Result FramebufferVk::copyResolveToMultisampedAttachment(ContextVk *conte
13421343
params.srcExtents[1] = extents.height;
13431344
params.destOffset[0] = 0;
13441345
params.destOffset[1] = 0;
1345-
params.srcMip = levelVK;
1346+
params.srcMip = levelVK.get();
13461347
params.srcLayer = layer;
13471348
params.srcHeight = extents.height;
13481349
params.srcPremultiplyAlpha = false;
@@ -2395,8 +2396,8 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
23952396
void *pixels)
23962397
{
23972398
ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl");
2398-
uint32_t levelGL = renderTarget->getLevelIndex();
2399-
uint32_t layer = renderTarget->getLayerIndex();
2399+
gl::LevelIndex levelGL = renderTarget->getLevelIndex();
2400+
uint32_t layer = renderTarget->getLayerIndex();
24002401
return renderTarget->getImageForCopy().readPixels(contextVk, area, packPixelsParams,
24012402
copyAspectFlags, levelGL, layer, pixels,
24022403
&mReadPixelBuffer);

src/libANGLE/renderer/vulkan/ImageVk.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ egl::Error ImageVk::initialize(const egl::Display *display)
6767
mOwnsImage = false;
6868

6969
mImageTextureType = mState.imageIndex.getType();
70-
mImageLevel = mState.imageIndex.getLevelIndex();
70+
mImageLevel = gl::LevelIndex(mState.imageIndex.getLevelIndex());
7171
mImageLayer = mState.imageIndex.hasLayer() ? mState.imageIndex.getLayerIndex() : 0;
7272
}
7373
else
@@ -108,7 +108,7 @@ egl::Error ImageVk::initialize(const egl::Display *display)
108108
mOwnsImage = false;
109109

110110
mImageTextureType = gl::TextureType::_2D;
111-
mImageLevel = 0;
111+
mImageLevel = gl::LevelIndex(0);
112112
mImageLayer = 0;
113113
}
114114

src/libANGLE/renderer/vulkan/ImageVk.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ class ImageVk : public ImageImpl
4040

4141
vk::ImageHelper *getImage() const { return mImage; }
4242
gl::TextureType getImageTextureType() const { return mImageTextureType; }
43-
uint32_t getImageLevel() const { return mImageLevel; }
43+
gl::LevelIndex getImageLevel() const { return mImageLevel; }
4444
uint32_t getImageLayer() const { return mImageLayer; }
4545

4646
private:
4747
gl::TextureType mImageTextureType;
48-
uint32_t mImageLevel;
48+
gl::LevelIndex mImageLevel;
4949
uint32_t mImageLayer;
5050

5151
bool mOwnsImage;

src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,11 @@ angle::Result MemoryObjectVk::createImage(ContextVk *contextVk,
204204
// ANGLE_external_objects_flags allows create flags to be specified by the application instead
205205
// of getting defaulted to zero. Note that the GL enum values constituting the bits of
206206
// |createFlags| are identical to their corresponding Vulkan value.
207-
ANGLE_TRY(image->initExternal(
208-
contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags, createFlags,
209-
vk::ImageLayout::Undefined, &externalMemoryImageCreateInfo, 0,
210-
static_cast<uint32_t>(levels) - 1, static_cast<uint32_t>(levels), layerCount));
207+
ANGLE_TRY(image->initExternal(contextVk, type, vkExtents, vkFormat, 1, imageUsageFlags,
208+
createFlags, vk::ImageLayout::Undefined,
209+
&externalMemoryImageCreateInfo, gl::LevelIndex(0),
210+
gl::LevelIndex(static_cast<uint32_t>(levels) - 1),
211+
static_cast<uint32_t>(levels), layerCount));
211212

212213
VkMemoryRequirements externalMemoryRequirements;
213214
image->getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);

src/libANGLE/renderer/vulkan/OverlayVk.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk)
110110
mFontImage.init(contextVk, gl::TextureType::_2D,
111111
VkExtent3D{gl::overlay::kFontImageWidth, gl::overlay::kFontImageHeight, 1},
112112
renderer->getFormat(angle::FormatID::R8_UNORM), 1,
113-
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0, 0, 1,
114-
gl::overlay::kFontCount));
113+
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
114+
gl::LevelIndex(0), gl::LevelIndex(0), 1, gl::overlay::kFontCount));
115115
ANGLE_TRY(mFontImage.initMemory(contextVk, renderer->getMemoryProperties(),
116116
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
117117
ANGLE_TRY(mFontImage.initImageView(contextVk, gl::TextureType::_2DArray,
118118
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
119-
&mFontImageView, 0, 1));
119+
&mFontImageView, vk::LevelIndex(0), 1));
120120

121121
// Copy font data from staging buffer.
122122
ANGLE_TRY(contextVk->onBufferTransferRead(&fontDataBuffer.get()));
@@ -177,13 +177,13 @@ angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
177177

178178
ANGLE_TRY(mCulledWidgets.init(contextVk, gl::TextureType::_2D, culledWidgetsExtent,
179179
renderer->getFormat(angle::FormatID::R32G32_UINT), 1,
180-
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0, 0, 1,
181-
1));
180+
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
181+
gl::LevelIndex(0), gl::LevelIndex(0), 1, 1));
182182
ANGLE_TRY(mCulledWidgets.initMemory(contextVk, renderer->getMemoryProperties(),
183183
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
184184
ANGLE_TRY(mCulledWidgets.initImageView(contextVk, gl::TextureType::_2D,
185185
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
186-
&mCulledWidgetsView, 0, 1));
186+
&mCulledWidgetsView, vk::LevelIndex(0), 1));
187187

188188
UtilsVk::OverlayCullParameters params;
189189
params.subgroupSize[0] = mSubgroupSize[0];

src/libANGLE/renderer/vulkan/RenderTargetVk.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void RenderTargetVk::init(vk::ImageHelper *image,
4141
vk::ImageViewHelper *imageViews,
4242
vk::ImageHelper *resolveImage,
4343
vk::ImageViewHelper *resolveImageViews,
44-
uint32_t levelIndexGL,
44+
gl::LevelIndex levelIndexGL,
4545
uint32_t layerIndex,
4646
bool isImageTransient)
4747
{
@@ -64,7 +64,7 @@ void RenderTargetVk::reset()
6464
mImageViews = nullptr;
6565
mResolveImage = nullptr;
6666
mResolveImageViews = nullptr;
67-
mLevelIndexGL = 0;
67+
mLevelIndexGL = gl::LevelIndex(0);
6868
mLayerIndex = 0;
6969
mContentDefined = false;
7070
}
@@ -74,7 +74,7 @@ vk::ImageViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
7474
{
7575
ASSERT(imageViews);
7676
ASSERT(mLayerIndex < std::numeric_limits<uint16_t>::max());
77-
ASSERT(mLevelIndexGL < std::numeric_limits<uint16_t>::max());
77+
ASSERT(mLevelIndexGL.get() < std::numeric_limits<uint16_t>::max());
7878

7979
vk::ImageViewSubresourceSerial imageViewSerial =
8080
imageViews->getSubresourceSerial(mLevelIndexGL, 1, mLayerIndex, vk::LayerMode::Single);
@@ -165,7 +165,7 @@ angle::Result RenderTargetVk::getImageViewImpl(ContextVk *contextVk,
165165
const vk::ImageView **imageViewOut) const
166166
{
167167
ASSERT(image.valid() && imageViews);
168-
int32_t levelVK = mLevelIndexGL - mImage->getBaseLevel();
168+
vk::LevelIndex levelVK = mImage->toVKLevel(mLevelIndexGL);
169169
return imageViews->getLevelLayerDrawImageView(contextVk, image, levelVK, mLayerIndex,
170170
imageViewOut);
171171
}
@@ -224,7 +224,7 @@ const vk::Format &RenderTargetVk::getImageFormat() const
224224
gl::Extents RenderTargetVk::getExtents() const
225225
{
226226
ASSERT(mImage && mImage->valid());
227-
uint32_t levelVK = mLevelIndexGL - mImage->getBaseLevel();
227+
vk::LevelIndex levelVK = mImage->toVKLevel(mLevelIndexGL);
228228
return mImage->getLevelExtents2D(levelVK);
229229
}
230230

@@ -306,16 +306,16 @@ gl::ImageIndex RenderTargetVk::getImageIndex() const
306306
// Determine the GL type from the Vk Image properties.
307307
if (mImage->getType() == VK_IMAGE_TYPE_3D)
308308
{
309-
return gl::ImageIndex::Make3D(mLevelIndexGL, mLayerIndex);
309+
return gl::ImageIndex::Make3D(mLevelIndexGL.get(), mLayerIndex);
310310
}
311311

312312
// We don't need to distinguish 2D array and cube.
313313
if (mImage->getLayerCount() > 1)
314314
{
315-
return gl::ImageIndex::Make2DArray(mLevelIndexGL, mLayerIndex);
315+
return gl::ImageIndex::Make2DArray(mLevelIndexGL.get(), mLayerIndex);
316316
}
317317

318318
ASSERT(mLayerIndex == 0);
319-
return gl::ImageIndex::Make2D(mLevelIndexGL);
319+
return gl::ImageIndex::Make2D(mLevelIndexGL.get());
320320
}
321321
} // namespace rx

src/libANGLE/renderer/vulkan/RenderTargetVk.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
4646
vk::ImageViewHelper *imageViews,
4747
vk::ImageHelper *resolveImage,
4848
vk::ImageViewHelper *resolveImageViews,
49-
uint32_t levelIndexGL,
49+
gl::LevelIndex levelIndexGL,
5050
uint32_t layerIndex,
5151
bool isImageTransient);
5252
void reset();
@@ -79,7 +79,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
7979

8080
const vk::Format &getImageFormat() const;
8181
gl::Extents getExtents() const;
82-
uint32_t getLevelIndex() const { return mLevelIndexGL; }
82+
gl::LevelIndex getLevelIndex() const { return mLevelIndexGL; }
8383
uint32_t getLayerIndex() const { return mLayerIndex; }
8484

8585
gl::ImageIndex getImageIndex() const;
@@ -133,7 +133,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
133133
vk::ImageViewHelper *mResolveImageViews;
134134

135135
// Which subresource of the image is used as render target.
136-
uint32_t mLevelIndexGL;
136+
gl::LevelIndex mLevelIndexGL;
137137
uint32_t mLayerIndex;
138138

139139
// Whether the render target has been invalidated. If so, DONT_CARE is used instead of LOAD for

src/libANGLE/renderer/vulkan/RenderbufferVk.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,13 @@ angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context,
8888

8989
VkExtent3D extents = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1u};
9090
ANGLE_TRY(mImage->init(contextVk, gl::TextureType::_2D, extents, vkFormat,
91-
static_cast<uint32_t>(samples), usage, 0, 0, 1, 1));
91+
static_cast<uint32_t>(samples), usage, gl::LevelIndex(0),
92+
gl::LevelIndex(0), 1, 1));
9293

9394
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
9495
ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
9596

96-
mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, 0, 0, false);
97+
mRenderTarget.init(mImage, &mImageViews, nullptr, nullptr, gl::LevelIndex(0), 0, false);
9798
}
9899

99100
return angle::Result::Continue;
@@ -245,8 +246,8 @@ angle::Result RenderbufferVk::getRenderbufferImage(const gl::Context *context,
245246
gl::MaybeOverrideLuminance(format, type, getColorReadFormat(context),
246247
getColorReadType(context));
247248

248-
return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, 0, 0, format, type,
249-
pixels);
249+
return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, gl::LevelIndex(0), 0,
250+
format, type, pixels);
250251
}
251252

252253
void RenderbufferVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)

0 commit comments

Comments
 (0)