Commit eae262e7 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix image layout barriers for tessellation shaders

Also fixes a bug where invalid stages may be specified for example if AllGraphicsReadOnly or DepthStencilReadOnly layouts are used and geometry or tessellation shaders are not supported by the implementation. Bug: angleproject:5557 Change-Id: Ia25a6aec8138c67701c63da65783263d8a7bda27 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2653911 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 6d86a0fe
......@@ -121,14 +121,18 @@ GLenum DefaultGLErrorCode(VkResult result)
constexpr gl::ShaderMap<vk::ImageLayout> kShaderReadOnlyImageLayouts = {
{gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderReadOnly},
{gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersReadOnly},
{gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersReadOnly},
{gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersReadOnly},
{gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderReadOnly},
{gl::ShaderType::Geometry, vk::ImageLayout::GeometryShaderReadOnly},
{gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderReadOnly}};
constexpr gl::ShaderMap<vk::ImageLayout> kShaderWriteImageLayouts = {
{gl::ShaderType::Vertex, vk::ImageLayout::VertexShaderWrite},
{gl::ShaderType::TessControl, vk::ImageLayout::PreFragmentShadersWrite},
{gl::ShaderType::TessEvaluation, vk::ImageLayout::PreFragmentShadersWrite},
{gl::ShaderType::Geometry, vk::ImageLayout::PreFragmentShadersWrite},
{gl::ShaderType::Fragment, vk::ImageLayout::FragmentShaderWrite},
{gl::ShaderType::Geometry, vk::ImageLayout::GeometryShaderWrite},
{gl::ShaderType::Compute, vk::ImageLayout::ComputeShaderWrite}};
constexpr VkBufferUsageFlags kVertexBufferUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
......@@ -1266,12 +1270,18 @@ ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
executable->getSamplerShaderBitsForTextureUnitIndex(textureUnit);
ASSERT(remainingShaderBits.any());
gl::ShaderType firstShader = remainingShaderBits.first();
gl::ShaderType lastShader = remainingShaderBits.last();
remainingShaderBits.reset(firstShader);
// If we have multiple shader accessing it, we barrier against all shader stage read
// given that we only support vertex/frag shaders
if (remainingShaderBits.any())
remainingShaderBits.reset(lastShader);
// We barrier against either:
// - Vertex only
// - Fragment only
// - Pre-fragment only (vertex, geometry and tessellation together)
if (remainingShaderBits.any() || firstShader != lastShader)
{
textureLayout = vk::ImageLayout::AllGraphicsShadersReadOnly;
textureLayout = lastShader == gl::ShaderType::Fragment
? vk::ImageLayout::AllGraphicsShadersReadOnly
: vk::ImageLayout::PreFragmentShadersReadOnly;
}
else
{
......@@ -1279,8 +1289,7 @@ ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
}
}
// Ensure the image is in read-only layout
commandBufferHelper->imageRead(&mResourceUseList, image.getAspectFlags(), textureLayout,
&image);
commandBufferHelper->imageRead(this, image.getAspectFlags(), textureLayout, &image);
textureVk->retainImageViews(&mResourceUseList);
}
......@@ -4284,16 +4293,23 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
alreadyProcessed.insert(image);
vk::ImageLayout imageLayout;
gl::ShaderType shader = static_cast<gl::ShaderType>(gl::ScanForward(shaderStages.bits()));
shaderStages.reset(shader);
// This is accessed by multiple shaders
if (shaderStages.any())
gl::ShaderType firstShader = shaderStages.first();
gl::ShaderType lastShader = shaderStages.last();
shaderStages.reset(firstShader);
shaderStages.reset(lastShader);
// We barrier against either:
// - Vertex only
// - Fragment only
// - Pre-fragment only (vertex, geometry and tessellation together)
if (shaderStages.any() || firstShader != lastShader)
{
imageLayout = vk::ImageLayout::AllGraphicsShadersWrite;
imageLayout = lastShader == gl::ShaderType::Fragment
? vk::ImageLayout::AllGraphicsShadersWrite
: vk::ImageLayout::PreFragmentShadersWrite;
}
else
{
imageLayout = kShaderWriteImageLayouts[shader];
imageLayout = kShaderWriteImageLayouts[firstShader];
}
VkImageAspectFlags aspectFlags = image->getAspectFlags();
......@@ -4307,8 +4323,8 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
}
commandBufferHelper->imageWrite(
&mResourceUseList, gl::LevelIndex(static_cast<uint32_t>(imageUnit.level)), layerStart,
layerCount, aspectFlags, imageLayout, vk::AliasingMode::Allowed, image);
this, gl::LevelIndex(static_cast<uint32_t>(imageUnit.level)), layerStart, layerCount,
aspectFlags, imageLayout, vk::AliasingMode::Allowed, image);
}
return angle::Result::Continue;
......@@ -5073,7 +5089,7 @@ angle::Result ContextVk::onResourceAccess(const vk::CommandBufferAccess &access)
{
ASSERT(!IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageAccess.image));
imageAccess.image->recordReadBarrier(imageAccess.aspectFlags, imageAccess.imageLayout,
imageAccess.image->recordReadBarrier(this, imageAccess.aspectFlags, imageAccess.imageLayout,
&mOutsideRenderPassCommands->getCommandBuffer());
imageAccess.image->retain(&mResourceUseList);
}
......@@ -5083,7 +5099,7 @@ angle::Result ContextVk::onResourceAccess(const vk::CommandBufferAccess &access)
ASSERT(!IsRenderPassStartedAndUsesImage(*mRenderPassCommands, *imageWrite.access.image));
imageWrite.access.image->recordWriteBarrier(
imageWrite.access.aspectFlags, imageWrite.access.imageLayout,
this, imageWrite.access.aspectFlags, imageWrite.access.imageLayout,
&mOutsideRenderPassCommands->getCommandBuffer());
imageWrite.access.image->retain(&mResourceUseList);
imageWrite.access.image->onWrite(imageWrite.levelStart, imageWrite.levelCount,
......
......@@ -447,7 +447,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
vk::ImageHelper *image)
{
ASSERT(mRenderPassCommands->started());
mRenderPassCommands->imageRead(&mResourceUseList, aspectFlags, imageLayout, image);
mRenderPassCommands->imageRead(this, aspectFlags, imageLayout, image);
}
void onImageRenderPassWrite(gl::LevelIndex level,
......@@ -458,8 +458,8 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
vk::ImageHelper *image)
{
ASSERT(mRenderPassCommands->started());
mRenderPassCommands->imageWrite(&mResourceUseList, level, layerStart, layerCount,
aspectFlags, imageLayout, vk::AliasingMode::Allowed, image);
mRenderPassCommands->imageWrite(this, level, layerStart, layerCount, aspectFlags,
imageLayout, vk::AliasingMode::Allowed, image);
}
void onDepthStencilDraw(gl::LevelIndex level,
......@@ -477,7 +477,7 @@ class ContextVk : public ContextImpl, public vk::Context, public MultisampleText
{
if (mRenderPassCommands->started())
{
mRenderPassCommands->onImageHelperRelease(image);
mRenderPassCommands->onImageHelperRelease(this, image);
}
}
......
......@@ -202,7 +202,7 @@ angle::Result RenderbufferVk::setStorageEGLImageTarget(const gl::Context *contex
{
vk::CommandBuffer *commandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
mImage->changeLayoutAndQueue(aspect, vk::ImageLayout::ColorAttachment,
mImage->changeLayoutAndQueue(contextVk, aspect, vk::ImageLayout::ColorAttachment,
rendererQueueFamilyIndex, commandBuffer);
}
......
......@@ -625,7 +625,8 @@ RendererVk::RendererVk()
mPipelineCacheDirty(false),
mPipelineCacheInitialized(false),
mCommandProcessor(this),
mGlslangInitialized(false)
mGlslangInitialized(false),
mSupportedVulkanPipelineStageMask(0)
{
VkFormatProperties invalid = {0, 0, kInvalidFormatFeatureFlags};
mFormatProperties.fill(invalid);
......@@ -1719,6 +1720,21 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
ANGLE_TRY(initPipelineCache(displayVk, &mPipelineCache, &success));
}
// Track the set of supported pipeline stages. This is used when issuing image layout
// transitions that cover many stages (such as AllGraphicsReadOnly) to mask out unsupported
// stages, which avoids enumerating every possible combination of stages in the layouts.
VkPipelineStageFlags unsupportedStages = 0;
if (!mPhysicalDeviceFeatures.tessellationShader)
{
unsupportedStages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
}
if (!mPhysicalDeviceFeatures.geometryShader)
{
unsupportedStages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
}
mSupportedVulkanPipelineStageMask = ~unsupportedStages;
return angle::Result::Continue;
}
......
......@@ -363,6 +363,11 @@ class RendererVk : angle::NonCopyable
// Log cache stats for all caches
void logCacheStats() const;
VkPipelineStageFlags getSupportedVulkanPipelineStageMask() const
{
return mSupportedVulkanPipelineStageMask;
}
private:
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
void ensureCapsInitialized() const;
......@@ -492,6 +497,17 @@ class RendererVk : angle::NonCopyable
// Stats about all Vulkan object caches
using VulkanCacheStats = angle::PackedEnumMap<VulkanCacheType, CacheStats>;
VulkanCacheStats mVulkanCacheStats;
// A mask to filter out Vulkan pipeline stages that are not supported, applied in situations
// where multiple stages are prespecified (for example with image layout transitions):
//
// - Excludes GEOMETRY if geometry shaders are not supported.
// - Excludes TESSELLATION_CONTROL and TESSELLATION_EVALUATION if tessellation shaders are not
// supported.
//
// Note that this mask can have bits set that don't correspond to valid stages, so it's strictly
// only useful for masking out unsupported stages in an otherwise valid set of stages.
VkPipelineStageFlags mSupportedVulkanPipelineStageMask;
};
} // namespace rx
......
......@@ -1336,7 +1336,7 @@ angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
}
// This does nothing if it's already in the requested layout
image.image.recordReadBarrier(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present,
image.image.recordReadBarrier(contextVk, VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present,
commandBuffer);
// Knowing that the kSwapHistorySize'th submission ago has finished, we can know that the
......
......@@ -1366,8 +1366,8 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
vk::CommandBuffer *commandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
mImage->changeLayoutAndQueue(mImage->getAspectFlags(), newLayout, rendererQueueFamilyIndex,
commandBuffer);
mImage->changeLayoutAndQueue(contextVk, mImage->getAspectFlags(), newLayout,
rendererQueueFamilyIndex, commandBuffer);
}
return angle::Result::Continue;
......
......@@ -995,11 +995,11 @@ class CommandBufferHelper : angle::NonCopyable
AliasingMode aliasingMode,
BufferHelper *buffer);
void imageRead(ResourceUseList *resourceUseList,
void imageRead(ContextVk *contextVk,
VkImageAspectFlags aspectFlags,
ImageLayout imageLayout,
ImageHelper *image);
void imageWrite(ResourceUseList *resourceUseList,
void imageWrite(ContextVk *contextVk,
gl::LevelIndex level,
uint32_t layerStart,
uint32_t layerCount,
......@@ -1053,7 +1053,7 @@ class CommandBufferHelper : angle::NonCopyable
return mRenderPassStarted;
}
void onImageHelperRelease(const ImageHelper *image);
void onImageHelperRelease(Context *context, const ImageHelper *image);
void beginRenderPass(const Framebuffer &framebuffer,
const gl::Rectangle &renderArea,
......@@ -1176,8 +1176,8 @@ class CommandBufferHelper : angle::NonCopyable
void restoreDepthContent();
void restoreStencilContent();
void finalizeDepthStencilImageLayout();
void finalizeDepthStencilResolveImageLayout();
void finalizeDepthStencilImageLayout(Context *context);
void finalizeDepthStencilResolveImageLayout(Context *context);
// Allocator used by this class. Using a pool allocator per CBH to avoid threading issues
// that occur w/ shared allocator between multiple CBHs.
......@@ -1286,8 +1286,9 @@ enum class ImageLayout
TransferDst,
VertexShaderReadOnly,
VertexShaderWrite,
GeometryShaderReadOnly,
GeometryShaderWrite,
// PreFragment == Vertex, Tessellation and Geometry stages
PreFragmentShadersReadOnly,
PreFragmentShadersWrite,
FragmentShaderReadOnly,
FragmentShaderWrite,
ComputeShaderReadOnly,
......@@ -1621,17 +1622,19 @@ class ImageHelper final : public Resource, public angle::Subject
uint32_t layerCount) const;
bool hasStagedUpdatesInAllocatedLevels() const;
void recordWriteBarrier(VkImageAspectFlags aspectMask,
void recordWriteBarrier(Context *context,
VkImageAspectFlags aspectMask,
ImageLayout newLayout,
CommandBuffer *commandBuffer)
{
barrierImpl(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
barrierImpl(context, aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
}
// This function can be used to prevent issuing redundant layout transition commands.
bool isReadBarrierNecessary(ImageLayout newLayout) const;
void recordReadBarrier(VkImageAspectFlags aspectMask,
void recordReadBarrier(Context *context,
VkImageAspectFlags aspectMask,
ImageLayout newLayout,
CommandBuffer *commandBuffer)
{
......@@ -1640,7 +1643,7 @@ class ImageHelper final : public Resource, public angle::Subject
return;
}
barrierImpl(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
barrierImpl(context, aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
}
bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const
......@@ -1648,13 +1651,15 @@ class ImageHelper final : public Resource, public angle::Subject
return mCurrentQueueFamilyIndex != newQueueFamilyIndex;
}
void changeLayoutAndQueue(VkImageAspectFlags aspectMask,
void changeLayoutAndQueue(Context *context,
VkImageAspectFlags aspectMask,
ImageLayout newLayout,
uint32_t newQueueFamilyIndex,
CommandBuffer *commandBuffer);
// Returns true if barrier has been generated
bool updateLayoutAndBarrier(VkImageAspectFlags aspectMask,
bool updateLayoutAndBarrier(Context *context,
VkImageAspectFlags aspectMask,
ImageLayout newLayout,
PipelineBarrier *barrier);
......@@ -1834,7 +1839,8 @@ class ImageHelper final : public Resource, public angle::Subject
// Generalized to accept both "primary" and "secondary" command buffers.
template <typename CommandBufferT>
void barrierImpl(VkImageAspectFlags aspectMask,
void barrierImpl(Context *context,
VkImageAspectFlags aspectMask,
ImageLayout newLayout,
uint32_t newQueueFamilyIndex,
CommandBufferT *commandBuffer);
......
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