Commit 0b9ebe58 by Jamie Madill Committed by Commit Bot

Vulkan: Add "ImageViewHelper".

This allows views to track a different lifetime than vk::ImageHelper. This in turn will fix the race condition on ContextVk destruction when releasing ImageViews owned by TextureVk and RenderbufferVk. For now this is a refactoring change only. Bug: angleproject:2464 Change-Id: I9581975bd5d4913233bbed8439dd4a632cc78a2a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1843231 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarIan Elliott <ianelliott@google.com>
parent 81ab9c90
......@@ -1472,8 +1472,8 @@ angle::Result ProgramVk::updateImagesDescriptorSet(ContextVk *contextVk,
vk::ImageHelper *image = &textureVk->getImage();
const vk::ImageView *imageView = nullptr;
ANGLE_TRY(textureVk->getLayerLevelStorageImageView(
contextVk, (binding.layered == GL_TRUE), binding.layer, binding.level, &imageView));
ANGLE_TRY(textureVk->getStorageImageView(contextVk, (binding.layered == GL_TRUE),
binding.level, binding.layer, &imageView));
// Note: binding.access is unused because it is implied by the shader.
......
......@@ -91,6 +91,9 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
uint32_t mLayerIndex;
};
// A vector of rendertargets
using RenderTargetVector = std::vector<RenderTargetVk>;
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_RENDERTARGETVK_H_
......@@ -78,17 +78,13 @@ angle::Result RenderbufferVk::setStorageImpl(const gl::Context *context,
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
// Note that LUMA textures are not color-renderable, so a read-view with swizzle is not
// needed.
ANGLE_TRY(mImage->initImageView(contextVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
&mImageView, 0, 1));
const vk::ImageView *imageView = nullptr;
ANGLE_TRY(mImageViews.getLevelLayerDrawImageView(contextVk, *mImage, 0, 0, &imageView));
// Clear the renderbuffer if it has emulated channels.
mImage->stageClearIfEmulatedFormat(gl::ImageIndex::Make2D(0), vkFormat);
mRenderTarget.init(mImage, &mImageView, 0, 0);
mRenderTarget.init(mImage, imageView, 0, 0);
}
return angle::Result::Continue;
......@@ -176,11 +172,11 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
imageVk->getImage()->getSamples());
}
ANGLE_TRY(mImage->initLayerImageView(contextVk, viewType, aspect, gl::SwizzleState(),
&mImageView, imageVk->getImageLevel(), 1,
imageVk->getImageLayer(), 1));
const vk::ImageView *imageView = nullptr;
ANGLE_TRY(mImageViews.getLevelLayerDrawImageView(contextVk, *mImage, imageVk->getImageLevel(),
imageVk->getImageLayer(), &imageView));
mRenderTarget.init(mImage, &mImageView, imageVk->getImageLevel(), imageVk->getImageLayer());
mRenderTarget.init(mImage, imageView, imageVk->getImageLevel(), imageVk->getImageLayer());
return angle::Result::Continue;
}
......@@ -232,7 +228,7 @@ void RenderbufferVk::releaseImage(ContextVk *contextVk)
mImage = nullptr;
}
contextVk->addGarbage(&mImageView);
mImageViews.release(contextVk);
}
} // namespace rx
......@@ -60,7 +60,7 @@ class RenderbufferVk : public RenderbufferImpl
bool mOwnsImage;
vk::ImageHelper *mImage;
vk::ImageView mImageView;
vk::ImageViewHelper mImageViews;
RenderTargetVk mRenderTarget;
};
......
......@@ -88,7 +88,8 @@ class OffscreenSurfaceVk : public SurfaceVk
void destroy(const egl::Display *display);
vk::ImageHelper image;
vk::ImageView imageView;
vk::ImageViewHelper imageViews;
const vk::ImageView *drawView = nullptr;
};
angle::Result initializeImpl(DisplayVk *displayVk);
......@@ -162,7 +163,8 @@ struct SwapchainImage : angle::NonCopyable
~SwapchainImage();
vk::ImageHelper image;
vk::ImageView imageView;
vk::ImageViewHelper imageViews;
const vk::ImageView *drawView = nullptr;
vk::Framebuffer framebuffer;
// A circular array of semaphores used for presenting this image.
......@@ -286,11 +288,11 @@ class WindowSurfaceVk : public SurfaceVk
// Depth/stencil image. Possibly multisampled.
vk::ImageHelper mDepthStencilImage;
vk::ImageView mDepthStencilImageView;
vk::ImageViewHelper mDepthStencilImageViews;
// Multisample color image, view and framebuffer, if multisampling enabled.
vk::ImageHelper mColorImageMS;
vk::ImageView mColorImageViewMS;
vk::ImageViewHelper mColorImageMSViews;
vk::Framebuffer mFramebufferMS;
};
......
......@@ -158,15 +158,11 @@ class TextureVk : public TextureImpl
// A special view for cube maps as a 2D array, used with shaders that do texelFetch() and for
// seamful cube map emulation.
const vk::ImageView &getFetchImageView() const;
angle::Result getLayerLevelDrawImageView(vk::Context *context,
size_t layer,
size_t level,
const vk::ImageView **imageViewOut);
angle::Result getLayerLevelStorageImageView(ContextVk *contextVk,
bool allLayers,
size_t singleLayer,
size_t level,
const vk::ImageView **imageViewOut);
angle::Result getStorageImageView(ContextVk *contextVk,
bool allLayers,
size_t level,
size_t singleLayer,
const vk::ImageView **imageViewOut);
const vk::Sampler &getSampler() const;
angle::Result ensureImageInitialized(ContextVk *contextVk);
......@@ -291,7 +287,6 @@ class TextureVk : public TextureImpl
const gl::Extents &extents,
const uint32_t levelCount);
void releaseImage(ContextVk *contextVk);
void releaseImageViews(ContextVk *contextVk);
void releaseStagingBuffer(ContextVk *contextVk);
uint32_t getLevelCount() const;
angle::Result initImageViews(ContextVk *contextVk,
......@@ -300,10 +295,10 @@ class TextureVk : public TextureImpl
uint32_t levelCount,
uint32_t layerCount);
angle::Result initRenderTargets(ContextVk *contextVk, GLuint layerCount, GLuint levelIndex);
vk::ImageView *getLevelImageViewImpl(vk::ImageViewVector *imageViews, size_t level);
vk::ImageView *getLayerLevelImageViewImpl(vk::LayerLevelImageViewVector *imageViews,
size_t layer,
size_t level);
angle::Result getLevelLayerImageView(vk::Context *context,
size_t level,
size_t layer,
const vk::ImageView **imageViewOut);
angle::Result ensureImageInitializedImpl(ContextVk *contextVk,
const gl::Extents &baseLevelExtents,
......@@ -326,24 +321,23 @@ class TextureVk : public TextureImpl
// mImage.
uint32_t mImageLevelOffset;
// |mImage| wraps a VkImage and VkDeviceMemory that represents the gl::Texture. |mOwnsImage|
// indicates that |TextureVk| owns the image. Otherwise it is a weak pointer shared with another
// class.
vk::ImageHelper *mImage;
// Read views.
vk::ImageView mReadImageView;
vk::ImageView mFetchImageView;
vk::ImageView mStencilReadImageView;
// Draw views.
vk::LayerLevelImageViewVector mLayerLevelDrawImageViews;
// Storage image views.
vk::ImageViewVector mLevelStorageImageViews;
// |mImageViews| contains all the current views for the Texture. The views are always owned by
// the Texture and are not shared like |mImage|. They also have different lifetimes and can be
// reallocated independently of |mImage| on state changes.
vk::ImageViewHelper mImageViews;
// |mSampler| contains the relevant Vulkan sampler states reprensenting the OpenGL Texture
// sampling states for the Texture.
vk::Sampler mSampler;
// Render targets stored as vector of vectors
// Level is first dimension, layer is second
std::vector<vk::RenderTargetVector> mRenderTargets;
std::vector<RenderTargetVector> mRenderTargets;
// The serial is used for cache indexing.
Serial mSerial;
......
......@@ -258,6 +258,33 @@ void HandlePrimitiveRestart(gl::DrawElementsType glIndexType,
UNREACHABLE();
}
}
bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
{
constexpr VkImageAspectFlags kDepthStencilAspects =
VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
return (aspectFlags & kDepthStencilAspects) == kDepthStencilAspects;
}
uint32_t GetImageLayerCountForView(const ImageHelper &image)
{
// Depth > 1 means this is a 3D texture and depth is our layer count
return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
}
ImageView *GetLevelImageView(ImageViewVector *imageViews, uint32_t level, uint32_t levelCount)
{
// Lazily allocate the storage for image views. We allocate the full level count because we
// don't want to trigger any std::vecotr reallocations. Reallocations could invalidate our
// view pointers.
if (imageViews->empty())
{
imageViews->resize(levelCount);
}
ASSERT(imageViews->size() > level);
return &(*imageViews)[level];
}
} // anonymous namespace
// DynamicBuffer implementation.
......@@ -1666,7 +1693,7 @@ angle::Result ImageHelper::initLayerImageView(Context *context,
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount)
uint32_t layerCount) const
{
VkImageViewCreateInfo viewInfo = {};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
......@@ -2862,6 +2889,161 @@ void FramebufferHelper::release(ContextVk *contextVk)
contextVk->addGarbage(&mFramebuffer);
}
// ImageViewHelper implementation.
ImageViewHelper::ImageViewHelper() = default;
ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
{
std::swap(mReadImageView, other.mReadImageView);
std::swap(mFetchImageView, other.mFetchImageView);
std::swap(mStencilReadImageView, other.mStencilReadImageView);
std::swap(mLevelDrawImageViews, other.mLevelDrawImageViews);
std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
}
ImageViewHelper::~ImageViewHelper() = default;
void ImageViewHelper::release(ContextVk *contextVk)
{
contextVk->addGarbage(&mReadImageView);
contextVk->addGarbage(&mFetchImageView);
contextVk->addGarbage(&mStencilReadImageView);
for (vk::ImageView &imageView : mLevelDrawImageViews)
{
contextVk->addGarbage(&imageView);
}
mLevelDrawImageViews.clear();
for (vk::ImageViewVector &layerViews : mLayerLevelDrawImageViews)
{
for (vk::ImageView &imageView : layerViews)
{
contextVk->addGarbage(&imageView);
}
}
mLayerLevelDrawImageViews.clear();
}
void ImageViewHelper::destroy(VkDevice device)
{
mReadImageView.destroy(device);
mFetchImageView.destroy(device);
mStencilReadImageView.destroy(device);
for (vk::ImageView &imageView : mLevelDrawImageViews)
{
imageView.destroy(device);
}
mLevelDrawImageViews.clear();
for (vk::ImageViewVector &layerViews : mLayerLevelDrawImageViews)
{
for (vk::ImageView &imageView : layerViews)
{
imageView.destroy(device);
}
}
mLayerLevelDrawImageViews.clear();
}
angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
gl::TextureType viewType,
const ImageHelper &image,
const Format &format,
const gl::SwizzleState &swizzleState,
uint32_t baseLevel,
uint32_t levelCount,
uint32_t baseLayer,
uint32_t layerCount)
{
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.angleFormat());
if (HasBothDepthAndStencilAspects(aspectFlags))
{
ANGLE_TRY(image.initLayerImageView(contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT,
swizzleState, &mReadImageView, baseLevel, levelCount,
baseLayer, layerCount));
ANGLE_TRY(image.initLayerImageView(contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT,
swizzleState, &mStencilReadImageView, baseLevel,
levelCount, baseLayer, layerCount));
}
else
{
ANGLE_TRY(image.initLayerImageView(contextVk, viewType, aspectFlags, swizzleState,
&mReadImageView, baseLevel, levelCount, baseLayer,
layerCount));
}
if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
viewType == gl::TextureType::_2DMultisampleArray)
{
gl::TextureType arrayType = vk::Get2DTextureType(layerCount, image.getSamples());
// TODO(http://anglebug.com/4004): SwizzleState incorrect for CopyTextureCHROMIUM.
ANGLE_TRY(image.initLayerImageView(contextVk, arrayType, aspectFlags, swizzleState,
&mFetchImageView, baseLevel, levelCount, baseLayer,
layerCount));
}
return angle::Result::Continue;
}
angle::Result ImageViewHelper::getLevelDrawImageView(ContextVk *contextVk,
gl::TextureType viewType,
const ImageHelper &image,
uint32_t level,
uint32_t layer,
const ImageView **imageViewOut)
{
// TODO(http://anglebug.com/4008): Possibly incorrect level count.
ImageView *imageView = GetLevelImageView(&mLevelDrawImageViews, level, 1);
*imageViewOut = imageView;
if (imageView->valid())
{
return angle::Result::Continue;
}
// Create the view. Note that storage images are not affected by swizzle parameters.
return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(),
imageView, level, 1, layer, image.getLayerCount());
}
angle::Result ImageViewHelper::getLevelLayerDrawImageView(Context *context,
const ImageHelper &image,
uint32_t level,
uint32_t layer,
const ImageView **imageViewOut)
{
ASSERT(image.valid());
ASSERT(!image.getFormat().imageFormat().isBlock);
uint32_t layerCount = GetImageLayerCountForView(image);
// Lazily allocate the storage for image views
if (mLayerLevelDrawImageViews.empty())
{
mLayerLevelDrawImageViews.resize(layerCount);
}
ASSERT(mLayerLevelDrawImageViews.size() > layer);
ImageView *imageView =
GetLevelImageView(&mLayerLevelDrawImageViews[layer], level, image.getLevelCount());
*imageViewOut = imageView;
if (imageView->valid())
{
return angle::Result::Continue;
}
// Lazily allocate the image view itself.
// Note that these views are specifically made to be used as color attachments, and therefore
// don't have swizzle.
gl::TextureType viewType = vk::Get2DTextureType(1, image.getSamples());
return image.initLayerImageView(context, viewType, image.getAspectFlags(), gl::SwizzleState(),
imageView, level, 1, layer, 1);
}
// FramebufferHelper implementation.
DispatchHelper::DispatchHelper() : CommandGraphResource(CommandGraphResourceType::Dispatcher) {}
......
......@@ -693,7 +693,7 @@ class ImageHelper final : public CommandGraphResource
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
uint32_t layerCount);
uint32_t layerCount) const;
angle::Result initImageView(Context *context,
gl::TextureType textureType,
VkImageAspectFlags aspectMask,
......@@ -972,6 +972,63 @@ class ImageHelper final : public CommandGraphResource
std::vector<SubresourceUpdate> mSubresourceUpdates;
};
// A vector of image views, such as one per level or one per layer.
using ImageViewVector = std::vector<ImageView>;
// A vector of vector of image views. Primary index is layer, secondary index is level.
using LayerLevelImageViewVector = std::vector<ImageViewVector>;
class ImageViewHelper : angle::NonCopyable
{
public:
ImageViewHelper();
ImageViewHelper(ImageViewHelper &&other);
~ImageViewHelper();
void release(ContextVk *contextVk);
void destroy(VkDevice device);
const ImageView &getReadImageView() const { return mReadImageView; }
const ImageView &getFetchImageView() const { return mFetchImageView; }
const ImageView &getStencilReadImageView() const { return mStencilReadImageView; }
// Creates views with multiple layers and levels.
angle::Result initReadViews(ContextVk *contextVk,
gl::TextureType viewType,
const ImageHelper &image,
const Format &format,
const gl::SwizzleState &swizzleState,
uint32_t baseLevel,
uint32_t levelCount,
uint32_t baseLayer,
uint32_t layerCount);
// Creates a view with all layers of the level.
angle::Result getLevelDrawImageView(ContextVk *contextVk,
gl::TextureType viewType,
const ImageHelper &image,
uint32_t level,
uint32_t layer,
const ImageView **imageViewOut);
// Creates a view with a single layer of the level.
angle::Result getLevelLayerDrawImageView(Context *context,
const ImageHelper &image,
uint32_t level,
uint32_t layer,
const ImageView **imageViewOut);
private:
// Read views.
ImageView mReadImageView;
ImageView mFetchImageView;
ImageView mStencilReadImageView;
// Draw views.
ImageViewVector mLevelDrawImageViews;
LayerLevelImageViewVector mLayerLevelDrawImageViews;
};
class FramebufferHelper : public CommandGraphResource
{
public:
......
......@@ -592,14 +592,6 @@ class Recycler final : angle::NonCopyable
bool SamplerNameContainsNonZeroArrayElement(const std::string &name);
std::string GetMappedSamplerName(const std::string &originalName);
// A vector of image views, such as one per level or one per layer.
using ImageViewVector = std::vector<ImageView>;
// A vector of vector of image views. Primary index is layer, secondary index is level.
using LayerLevelImageViewVector = std::vector<ImageViewVector>;
// A vector of rendertargets
using RenderTargetVector = std::vector<RenderTargetVk>;
} // namespace vk
// List of function pointers for used extensions.
......
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