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;
};
......
......@@ -148,11 +148,7 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(image.initMemory(displayVk, renderer->getMemoryProperties(), flags));
VkImageAspectFlags aspect = vk::GetFormatAspectFlags(textureFormat);
ANGLE_TRY(image.initImageView(displayVk, gl::TextureType::_2D, aspect, gl::SwizzleState(),
&imageView, 0, 1));
ANGLE_TRY(imageViews.getLevelLayerDrawImageView(displayVk, image, 0, 0, &drawView));
// Clear the image if it has emulated channels.
image.stageClearIfEmulatedFormat(gl::ImageIndex::Make2D(0), vkFormat);
......@@ -169,18 +165,14 @@ void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display)
// destruction. If this assumption is incorrect, we could use the last submit serial
// to determine when to destroy the surface.
image.destroy(device);
imageView.destroy(device);
imageViews.destroy(device);
}
OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState,
EGLint width,
EGLint height)
: SurfaceVk(surfaceState), mWidth(width), mHeight(height)
{
mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageView, 0, 0);
mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
&mDepthStencilAttachment.imageView, 0, 0);
}
{}
OffscreenSurfaceVk::~OffscreenSurfaceVk() {}
......@@ -203,12 +195,15 @@ angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk)
{
ANGLE_TRY(mColorAttachment.initialize(
displayVk, mWidth, mHeight, renderer->getFormat(config->renderTargetFormat), samples));
mColorRenderTarget.init(&mColorAttachment.image, mColorAttachment.drawView, 0, 0);
}
if (config->depthStencilFormat != GL_NONE)
{
ANGLE_TRY(mDepthStencilAttachment.initialize(
displayVk, mWidth, mHeight, renderer->getFormat(config->depthStencilFormat), samples));
mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
mDepthStencilAttachment.drawView, 0, 0);
}
return angle::Result::Continue;
......@@ -363,7 +358,7 @@ SwapchainImage::~SwapchainImage() = default;
SwapchainImage::SwapchainImage(SwapchainImage &&other)
: image(std::move(other.image)),
imageView(std::move(other.imageView)),
imageViews(std::move(other.imageViews)),
framebuffer(std::move(other.framebuffer)),
presentHistory(std::move(other.presentHistory)),
currentPresentHistoryIndex(other.currentPresentHistoryIndex)
......@@ -405,12 +400,7 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR),
mCurrentSwapHistoryIndex(0),
mCurrentSwapchainImageIndex(0)
{
// Initialize the color render target with the multisampled targets. If not multisampled, the
// render target will be updated to refer to a swapchain image on every acquire.
mColorRenderTarget.init(&mColorImageMS, &mColorImageViewMS, 0, 0);
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, 0);
}
{}
WindowSurfaceVk::~WindowSurfaceVk()
{
......@@ -776,9 +766,13 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
ANGLE_TRY(mColorImageMS.initMemory(context, renderer->getMemoryProperties(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
ANGLE_TRY(mColorImageMS.initImageView(context, gl::TextureType::_2D,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
&mColorImageViewMS, 0, 1));
const vk::ImageView *msDrawView = nullptr;
ANGLE_TRY(mColorImageMSViews.getLevelLayerDrawImageView(context, mColorImageMS, 0, 0,
&msDrawView));
// Initialize the color render target with the multisampled targets. If not multisampled,
// the render target will be updated to refer to a swapchain image on every acquire.
mColorRenderTarget.init(&mColorImageMS, msDrawView, 0, 0);
// Clear the image if it has emulated channels.
mColorImageMS.stageClearIfEmulatedFormat(gl::ImageIndex::Make2D(0), format);
......@@ -796,9 +790,8 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
// If the multisampled image is used, we don't need a view on the swapchain image, as
// it's only used as a resolve destination. This has the added benefit that we can't
// accidentally use this image.
ANGLE_TRY(member.image.initImageView(context, gl::TextureType::_2D,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
&member.imageView, 0, 1));
ANGLE_TRY(member.imageViews.getLevelLayerDrawImageView(context, member.image, 0, 0,
&member.drawView));
// Clear the image if it has emulated channels. If a multisampled image exists, this
// image will be unused until a pre-present resolve, at which point it will be fully
......@@ -819,11 +812,11 @@ angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
ANGLE_TRY(mDepthStencilImage.initMemory(context, renderer->getMemoryProperties(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
const VkImageAspectFlags aspect = vk::GetDepthStencilAspectFlags(dsFormat.imageFormat());
const vk::ImageView *dsDrawView = nullptr;
ANGLE_TRY(mDepthStencilImageViews.getLevelLayerDrawImageView(context, mDepthStencilImage, 0,
0, &dsDrawView));
ANGLE_TRY(mDepthStencilImage.initImageView(context, gl::TextureType::_2D, aspect,
gl::SwizzleState(), &mDepthStencilImageView, 0,
1));
mDepthStencilRenderTarget.init(&mDepthStencilImage, dsDrawView, 0, 0);
// We will need to pass depth/stencil image views to the RenderTargetVk in the future.
......@@ -893,19 +886,14 @@ void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk)
{
mDepthStencilImage.releaseImage(renderer);
mDepthStencilImage.releaseStagingBuffer(renderer);
if (mDepthStencilImageView.valid())
{
contextVk->addGarbage(&mDepthStencilImageView);
}
mDepthStencilImageViews.release(contextVk);
}
if (mColorImageMS.valid())
{
mColorImageMS.releaseImage(renderer);
mColorImageMS.releaseStagingBuffer(renderer);
contextVk->addGarbage(&mColorImageViewMS);
mColorImageMSViews.release(contextVk);
contextVk->addGarbage(&mFramebufferMS);
}
......@@ -915,7 +903,7 @@ void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk)
swapchainImage.image.resetImageWeakReference();
swapchainImage.image.destroy(contextVk->getDevice());
contextVk->addGarbage(&swapchainImage.imageView);
swapchainImage.imageViews.release(contextVk);
contextVk->addGarbage(&swapchainImage.framebuffer);
// present history must have already been taken care of.
......@@ -934,9 +922,9 @@ void WindowSurfaceVk::destroySwapChainImages(DisplayVk *displayVk)
VkDevice device = displayVk->getDevice();
mDepthStencilImage.destroy(device);
mDepthStencilImageView.destroy(device);
mDepthStencilImageViews.destroy(device);
mColorImageMS.destroy(device);
mColorImageViewMS.destroy(device);
mColorImageMSViews.destroy(device);
mFramebufferMS.destroy(device);
for (SwapchainImage &swapchainImage : mSwapchainImages)
......@@ -944,7 +932,7 @@ void WindowSurfaceVk::destroySwapChainImages(DisplayVk *displayVk)
// We don't own the swapchain image handles, so we just remove our reference to it.
swapchainImage.image.resetImageWeakReference();
swapchainImage.image.destroy(device);
swapchainImage.imageView.destroy(device);
swapchainImage.imageViews.destroy(device);
swapchainImage.framebuffer.destroy(device);
for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
......@@ -1198,7 +1186,7 @@ VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context)
// multisampling, as the swapchain image is essentially unused until then.
if (!mColorImageMS.valid())
{
mColorRenderTarget.updateSwapchainImage(&image.image, &image.imageView);
mColorRenderTarget.updateSwapchainImage(&image.image, image.drawView);
}
return VK_SUCCESS;
......@@ -1313,7 +1301,12 @@ angle::Result WindowSurfaceVk::getCurrentFramebuffer(vk::Context *context,
VkFramebufferCreateInfo framebufferInfo = {};
const gl::Extents extents = mColorRenderTarget.getExtents();
std::array<VkImageView, 2> imageViews = {{VK_NULL_HANDLE, mDepthStencilImageView.getHandle()}};
std::array<VkImageView, 2> imageViews = {};
if (mDepthStencilImage.valid())
{
imageViews[1] = mDepthStencilRenderTarget.getDrawImageView()->getHandle();
}
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.flags = 0;
......@@ -1327,14 +1320,14 @@ angle::Result WindowSurfaceVk::getCurrentFramebuffer(vk::Context *context,
if (isMultiSampled())
{
// If multisampled, there is only a single color image and framebuffer.
imageViews[0] = mColorImageViewMS.getHandle();
imageViews[0] = mColorRenderTarget.getDrawImageView()->getHandle();
ANGLE_VK_TRY(context, mFramebufferMS.init(context->getDevice(), framebufferInfo));
}
else
{
for (SwapchainImage &swapchainImage : mSwapchainImages)
{
imageViews[0] = swapchainImage.imageView.getHandle();
imageViews[0] = swapchainImage.drawView->getHandle();
ANGLE_VK_TRY(context,
swapchainImage.framebuffer.init(context->getDevice(), framebufferInfo));
}
......@@ -1399,7 +1392,7 @@ angle::Result WindowSurfaceVk::updateAndDrawOverlay(ContextVk *contextVk,
}
// Draw overlay
ANGLE_TRY(overlayVk->onPresent(contextVk, &image->image, &image->imageView));
ANGLE_TRY(overlayVk->onPresent(contextVk, &image->image, image->drawView));
overlay->getRunningGraphWidget(gl::WidgetId::VulkanCommandGraphSize)->next();
......
......@@ -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;
};
......
......@@ -66,12 +66,6 @@ bool ForceCPUPathForCopy(RendererVk *renderer, const vk::ImageHelper &image)
return image.getLayerCount() > 1 && renderer->getFeatures().forceCPUPathForCubeMapCopy.enabled;
}
uint32_t GetImageLayerCountForView(const vk::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();
}
void GetRenderTargetLayerCountAndIndex(vk::ImageHelper *image,
const gl::ImageIndex &index,
GLuint *layerCount,
......@@ -103,13 +97,6 @@ void GetRenderTargetLayerCountAndIndex(vk::ImageHelper *image,
UNREACHABLE();
}
}
bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
{
constexpr VkImageAspectFlags kDepthStencilAspects =
VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
return (aspectFlags & kDepthStencilAspects) == kDepthStencilAspects;
}
} // anonymous namespace
// TextureVk implementation.
......@@ -664,8 +651,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
params.srcLayer = layerIndex;
const vk::ImageView *destView;
ANGLE_TRY(
getLayerLevelDrawImageView(contextVk, baseLayer + layerIndex, level, &destView));
ANGLE_TRY(getLevelLayerImageView(contextVk, level, baseLayer + layerIndex, &destView));
ANGLE_TRY(utilsVk.copyImage(contextVk, mImage, destView, srcImage, srcView, params));
}
......@@ -900,7 +886,7 @@ void TextureVk::setImageHelper(ContextVk *contextVk,
mStagingBufferInitialSize);
// Force re-creation of render targets next time they are needed
for (vk::RenderTargetVector &renderTargetLevels : mRenderTargets)
for (RenderTargetVector &renderTargetLevels : mRenderTargets)
{
renderTargetLevels.clear();
}
......@@ -1329,7 +1315,7 @@ angle::Result TextureVk::initRenderTargets(ContextVk *contextVk,
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{
const vk::ImageView *drawView;
ANGLE_TRY(getLayerLevelDrawImageView(contextVk, layerIndex, levelIndex, &drawView));
ANGLE_TRY(getLevelLayerImageView(contextVk, levelIndex, layerIndex, &drawView));
mRenderTargets[levelIndex][layerIndex].init(
mImage, drawView, getNativeImageLevel(levelIndex), getNativeImageLayer(layerIndex));
}
......@@ -1375,7 +1361,7 @@ angle::Result TextureVk::syncState(const gl::Context *context,
uint32_t layerCount =
mState.getType() == gl::TextureType::_2D ? 1 : mImage->getLayerCount();
releaseImageViews(contextVk);
mImageViews.release(contextVk);
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
ANGLE_TRY(initImageViews(contextVk, mImage->getFormat(),
......@@ -1474,12 +1460,12 @@ const vk::ImageView &TextureVk::getReadImageView() const
{
ASSERT(mImage->valid());
if (mState.isStencilMode() && mStencilReadImageView.valid())
if (mState.isStencilMode() && mImageViews.getStencilReadImageView().valid())
{
return mStencilReadImageView;
return mImageViews.getStencilReadImageView();
}
return mReadImageView;
return mImageViews.getReadImageView();
}
const vk::ImageView &TextureVk::getFetchImageView() const
......@@ -1487,100 +1473,41 @@ const vk::ImageView &TextureVk::getFetchImageView() const
ASSERT(mImage->valid());
// We don't currently support fetch for depth/stencil cube map textures.
ASSERT(!mStencilReadImageView.valid() || !mFetchImageView.valid());
return (mFetchImageView.valid() ? mFetchImageView : mReadImageView);
ASSERT(!mImageViews.getStencilReadImageView().valid() ||
!mImageViews.getFetchImageView().valid());
return (mImageViews.getFetchImageView().valid() ? mImageViews.getFetchImageView()
: mImageViews.getReadImageView());
}
vk::ImageView *TextureVk::getLayerLevelImageViewImpl(vk::LayerLevelImageViewVector *imageViews,
size_t layer,
size_t level)
angle::Result TextureVk::getLevelLayerImageView(vk::Context *context,
size_t level,
size_t layer,
const vk::ImageView **imageViewOut)
{
ASSERT(mImage->valid());
ASSERT(!mImage->getFormat().imageFormat().isBlock);
ASSERT(mImage && mImage->valid());
uint32_t layerCount = GetImageLayerCountForView(*mImage);
// Lazily allocate the storage for image views
if (imageViews->empty())
{
imageViews->resize(layerCount);
}
ASSERT(imageViews->size() > layer);
return getLevelImageViewImpl(&(*imageViews)[layer], level);
}
vk::ImageView *TextureVk::getLevelImageViewImpl(vk::ImageViewVector *imageViews, size_t level)
{
// Lazily allocate the storage for image views
if (imageViews->empty())
{
imageViews->resize(mImage->getLevelCount());
}
ASSERT(imageViews->size() > level);
uint32_t nativeLevel = getNativeImageLevel(static_cast<uint32_t>(level));
uint32_t nativeLayer = getNativeImageLayer(static_cast<uint32_t>(layer));
return &(*imageViews)[level];
return mImageViews.getLevelLayerDrawImageView(context, *mImage, nativeLevel, nativeLayer,
imageViewOut);
}
angle::Result TextureVk::getLayerLevelDrawImageView(vk::Context *context,
size_t layer,
size_t level,
const vk::ImageView **imageViewOut)
angle::Result TextureVk::getStorageImageView(ContextVk *contextVk,
bool allLayers,
size_t level,
size_t singleLayer,
const vk::ImageView **imageViewOut)
{
vk::ImageView *imageView = getLayerLevelImageViewImpl(&mLayerLevelDrawImageViews, layer, level);
*imageViewOut = imageView;
if (imageView->valid())
if (!allLayers)
{
return angle::Result::Continue;
return getLevelLayerImageView(contextVk, level, singleLayer, imageViewOut);
}
// 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, mImage->getSamples());
return mImage->initLayerImageView(context, viewType, mImage->getAspectFlags(),
gl::SwizzleState(), imageView,
getNativeImageLevel(static_cast<uint32_t>(level)), 1,
getNativeImageLayer(static_cast<uint32_t>(layer)), 1);
}
angle::Result TextureVk::getLayerLevelStorageImageView(ContextVk *contextVk,
bool allLayers,
size_t singleLayer,
size_t level,
const vk::ImageView **imageViewOut)
{
gl::TextureType viewType = mState.getType();
uint32_t nativeLevel = getNativeImageLevel(static_cast<uint32_t>(level));
uint32_t nativeLayer = getNativeImageLayer(static_cast<uint32_t>(singleLayer));
uint32_t layerCount = 1;
vk::ImageView *imageView = nullptr;
if (allLayers)
{
// Ignore the layer parameter and create a view with all layers of the level.
imageView = getLevelImageViewImpl(&mLevelStorageImageViews, level);
// If layered, the view has the same type as the texture.
nativeLayer = getNativeImageLayer(0);
layerCount = mImage->getLayerCount();
}
else
{
return getLayerLevelDrawImageView(contextVk, singleLayer, level, imageViewOut);
}
*imageViewOut = imageView;
if (imageView->valid())
{
return angle::Result::Continue;
}
// Create the view. Note that storage images are not affected by swizzle parameters.
return mImage->initLayerImageView(contextVk, viewType, mImage->getAspectFlags(),
gl::SwizzleState(), imageView, nativeLevel, 1, nativeLayer,
layerCount);
uint32_t nativeLevel = getNativeImageLevel(static_cast<uint32_t>(level));
uint32_t nativeLayer = getNativeImageLayer(0);
return mImageViews.getLevelDrawImageView(contextVk, mState.getType(), *mImage, nativeLevel,
nativeLayer, imageViewOut);
}
const vk::Sampler &TextureVk::getSampler() const
......@@ -1659,41 +1586,17 @@ angle::Result TextureVk::initImageViews(ContextVk *contextVk,
uint32_t levelCount,
uint32_t layerCount)
{
ASSERT(mImage != nullptr && mImage->valid());
// TODO(cnorthrop): May be missing non-zero base level http://anglebug.com/3948
uint32_t baseLevel = getNativeImageLevel(0);
uint32_t baseLayer = getNativeImageLayer(0);
gl::SwizzleState mappedSwizzle;
MapSwizzleState(contextVk, format, sized, mState.getSwizzleState(), &mappedSwizzle);
const VkImageAspectFlags aspectFlags = vk::GetFormatAspectFlags(format.angleFormat());
if (HasBothDepthAndStencilAspects(aspectFlags))
{
ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), VK_IMAGE_ASPECT_DEPTH_BIT,
mappedSwizzle, &mReadImageView, baseLevel, levelCount,
baseLayer, layerCount));
ANGLE_TRY(mImage->initLayerImageView(
contextVk, mState.getType(), VK_IMAGE_ASPECT_STENCIL_BIT, mappedSwizzle,
&mStencilReadImageView, baseLevel, levelCount, baseLayer, layerCount));
}
else
{
ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), aspectFlags,
mappedSwizzle, &mReadImageView, baseLevel, levelCount,
baseLayer, layerCount));
}
if (mState.getType() == gl::TextureType::CubeMap ||
mState.getType() == gl::TextureType::_2DArray ||
mState.getType() == gl::TextureType::_2DMultisampleArray)
{
gl::TextureType arrayType = vk::Get2DTextureType(layerCount, mImage->getSamples());
ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, aspectFlags, mappedSwizzle,
&mFetchImageView, baseLevel, levelCount, baseLayer,
layerCount));
}
return angle::Result::Continue;
return mImageViews.initReadViews(contextVk, mState.getType(), *mImage, format, mappedSwizzle,
baseLevel, levelCount, baseLayer, layerCount);
}
void TextureVk::releaseImage(ContextVk *contextVk)
......@@ -1710,9 +1613,9 @@ void TextureVk::releaseImage(ContextVk *contextVk)
}
}
releaseImageViews(contextVk);
mImageViews.release(contextVk);
for (vk::RenderTargetVector &renderTargetLevels : mRenderTargets)
for (RenderTargetVector &renderTargetLevels : mRenderTargets)
{
// Clear the layers tracked for each level
renderTargetLevels.clear();
......@@ -1723,27 +1626,6 @@ void TextureVk::releaseImage(ContextVk *contextVk)
onStagingBufferChange();
}
void TextureVk::releaseImageViews(ContextVk *contextVk)
{
contextVk->addGarbage(&mReadImageView);
contextVk->addGarbage(&mFetchImageView);
contextVk->addGarbage(&mStencilReadImageView);
for (vk::ImageViewVector &layerViews : mLayerLevelDrawImageViews)
{
for (vk::ImageView &imageView : layerViews)
{
contextVk->addGarbage(&imageView);
}
}
mLayerLevelDrawImageViews.clear();
for (vk::ImageView &imageView : mLevelStorageImageViews)
{
contextVk->addGarbage(&imageView);
}
mLevelStorageImageViews.clear();
}
void TextureVk::releaseStagingBuffer(ContextVk *contextVk)
{
if (mImage)
......
......@@ -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