Commit d201ed8b by Jamie Madill Committed by Commit Bot

Vulkan: Track used Images in RenderPass.

Adding a simple ImageSerial tracking map in our RenderPass allows us to know when we do or do not need to close the RenderPass on a new Image access. This simple tracking scheme improves Manhattan performance by up to 25% on Android. The improved perf comes from reducing our RenderPass count (23->18 RenderPasses in our capture scene). Adds a FastUnorderedSet class to manage the used RP Image serials. Updates the Query helpers to explicitly flush the RP before inserting queries. Bug: angleproject:4911 Change-Id: I0c34fc8e307514ebdf3e81e08d8e5aedb70ebe8f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2334346Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 3e57e349
...@@ -474,6 +474,36 @@ class FastUnorderedMap final ...@@ -474,6 +474,36 @@ class FastUnorderedMap final
FastVector<Pair, N> mData; FastVector<Pair, N> mData;
}; };
template <class T, size_t N>
class FastUnorderedSet final
{
public:
FastUnorderedSet() {}
~FastUnorderedSet() {}
bool empty() const { return mData.empty(); }
void insert(T value)
{
ASSERT(!contains(value));
mData.push_back(value);
}
bool contains(T needle) const
{
for (T value : mData)
{
if (value == needle)
return true;
}
return false;
}
void clear() { mData.clear(); }
private:
FastVector<T, N> mData;
};
} // namespace angle } // namespace angle
#endif // COMMON_FASTVECTOR_H_ #endif // COMMON_FASTVECTOR_H_
...@@ -264,4 +264,29 @@ TEST(FastUnorderedMap, BasicUsage) ...@@ -264,4 +264,29 @@ TEST(FastUnorderedMap, BasicUsage)
EXPECT_FALSE(value); EXPECT_FALSE(value);
} }
} }
// Basic functionality for FastUnorderedSet
TEST(FastUnorderedSet, BasicUsage)
{
FastUnorderedSet<int, 3> testMap;
EXPECT_TRUE(testMap.empty());
testMap.insert(5);
EXPECT_TRUE(testMap.contains(5));
EXPECT_FALSE(testMap.contains(6));
EXPECT_FALSE(testMap.empty());
testMap.clear();
EXPECT_TRUE(testMap.empty());
for (int i = 0; i < 10; ++i)
{
testMap.insert(i);
}
for (int i = 0; i < 10; ++i)
{
EXPECT_TRUE(testMap.contains(i));
}
}
} // namespace angle } // namespace angle
...@@ -533,20 +533,17 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -533,20 +533,17 @@ class ContextVk : public ContextImpl, public vk::Context
vk::ImageHelper *image) vk::ImageHelper *image)
{ {
ASSERT(mRenderPassCommands->started()); ASSERT(mRenderPassCommands->started());
mRenderPassCommands->imageWrite(&mResourceUseList, aspectFlags, imageLayout, image); mRenderPassCommands->imageWrite(&mResourceUseList, aspectFlags, imageLayout,
vk::AliasingMode::Allowed, image);
} }
angle::Result getOutsideRenderPassCommandBuffer(vk::CommandBuffer **commandBufferOut) angle::Result getOutsideRenderPassCommandBuffer(vk::CommandBuffer **commandBufferOut)
{ {
// Only one command buffer should be active at a time
// TODO(jmadill): Do not end RenderPass. http://anglebug.com/4911
ASSERT(mOutsideRenderPassCommands->empty() || mRenderPassCommands->empty());
ANGLE_TRY(endRenderPass());
*commandBufferOut = &mOutsideRenderPassCommands->getCommandBuffer(); *commandBufferOut = &mOutsideRenderPassCommands->getCommandBuffer();
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result flushAndBeginRenderPass(const vk::Framebuffer &framebuffer, angle::Result beginNewRenderPass(const vk::Framebuffer &framebuffer,
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const vk::RenderPassDesc &renderPassDesc, const vk::RenderPassDesc &renderPassDesc,
const vk::AttachmentOpsArray &renderPassAttachmentOps, const vk::AttachmentOpsArray &renderPassAttachmentOps,
...@@ -580,7 +577,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -580,7 +577,7 @@ class ContextVk : public ContextImpl, public vk::Context
egl::ContextPriority getContextPriority() const override { return mContextPriority; } egl::ContextPriority getContextPriority() const override { return mContextPriority; }
angle::Result startRenderPass(gl::Rectangle renderArea, vk::CommandBuffer **commandBufferOut); angle::Result startRenderPass(gl::Rectangle renderArea, vk::CommandBuffer **commandBufferOut);
angle::Result endRenderPass(); angle::Result flushCommandsAndEndRenderPass();
angle::Result syncExternalMemory(); angle::Result syncExternalMemory();
...@@ -910,6 +907,8 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -910,6 +907,8 @@ class ContextVk : public ContextImpl, public vk::Context
// Pull an available CBH ptr from the CBH queue and set to specified hasRenderPass state // Pull an available CBH ptr from the CBH queue and set to specified hasRenderPass state
void getNextAvailableCommandBuffer(vk::CommandBufferHelper **commandBuffer, bool hasRenderPass); void getNextAvailableCommandBuffer(vk::CommandBufferHelper **commandBuffer, bool hasRenderPass);
angle::Result endRenderPassIfImageUsed(const vk::ImageHelper &image);
angle::Result endRenderPassIfTransformFeedbackBuffer(const vk::BufferHelper *buffer); angle::Result endRenderPassIfTransformFeedbackBuffer(const vk::BufferHelper *buffer);
void populateTransformFeedbackBufferSet( void populateTransformFeedbackBufferSet(
...@@ -1125,7 +1124,7 @@ ANGLE_INLINE angle::Result ContextVk::endRenderPassIfTransformFeedbackBuffer( ...@@ -1125,7 +1124,7 @@ ANGLE_INLINE angle::Result ContextVk::endRenderPassIfTransformFeedbackBuffer(
return angle::Result::Continue; return angle::Result::Continue;
} }
return endRenderPass(); return flushCommandsAndEndRenderPass();
} }
ANGLE_INLINE angle::Result ContextVk::onIndexBufferChange( ANGLE_INLINE angle::Result ContextVk::onIndexBufferChange(
......
...@@ -464,35 +464,25 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context, ...@@ -464,35 +464,25 @@ angle::Result FramebufferVk::clearImpl(const gl::Context *context,
vk::Framebuffer *currentFramebuffer = nullptr; vk::Framebuffer *currentFramebuffer = nullptr;
ANGLE_TRY(getFramebuffer(contextVk, &currentFramebuffer)); ANGLE_TRY(getFramebuffer(contextVk, &currentFramebuffer));
gl::DrawBufferMask clearColorDrawBuffersMask;
if (clearColorWithRenderPassLoadOp)
{
clearColorDrawBuffersMask = clearColorBuffers;
}
// If we are in an active renderpass that has recorded commands and the framebuffer hasn't // If we are in an active renderpass that has recorded commands and the framebuffer hasn't
// changed, inline the clear // changed, inline the clear
if (contextVk->hasStartedRenderPassWithCommands() && if (contextVk->hasStartedRenderPassWithCommands() &&
contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer)) contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer))
{ {
// Have active renderpass, add inline clear clearWithCommand(&contextVk->getStartedRenderPassCommands().getCommandBuffer(),
gl::DrawBufferMask clearBuffersWithInlineClear; scissoredRenderArea, clearColorDrawBuffersMask,
if (clearColorWithRenderPassLoadOp) clearDepthWithRenderPassLoadOp, clearStencilWithRenderPassLoadOp,
{ clearColorValue, clearDepthStencilValue);
clearBuffersWithInlineClear = clearColorBuffers;
}
clearWithClearAttachment(
&contextVk->getStartedRenderPassCommands().getCommandBuffer(), scissoredRenderArea,
clearBuffersWithInlineClear, clearDepthWithRenderPassLoadOp,
clearStencilWithRenderPassLoadOp, clearColorValue, clearDepthStencilValue);
} }
else else
{ {
// Clearing color is indicated by the set bits in this mask. If not clearing colors clearWithLoadOp(contextVk, clearColorDrawBuffersMask, clearDepthWithRenderPassLoadOp,
// with render pass loadOp, the default value of all-zeros means the clear is not done
// in clearWithRenderPassOp below. In that case, only clear depth/stencil with render
// pass loadOp.
gl::DrawBufferMask clearBuffersWithRenderPassLoadOp;
if (clearColorWithRenderPassLoadOp)
{
clearBuffersWithRenderPassLoadOp = clearColorBuffers;
}
clearWithRenderPassOp(clearBuffersWithRenderPassLoadOp, clearDepthWithRenderPassLoadOp,
clearStencilWithRenderPassLoadOp, clearColorValue, clearStencilWithRenderPassLoadOp, clearColorValue,
clearDepthStencilValue); clearDepthStencilValue);
} }
...@@ -1406,7 +1396,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk, ...@@ -1406,7 +1396,7 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
// tests this pattern, this optimization may not be necessary if no application does this. // tests this pattern, this optimization may not be necessary if no application does this.
// It is expected that an application would invalidate() when it's done with the // It is expected that an application would invalidate() when it's done with the
// framebuffer, so the render pass would have closed either way. // framebuffer, so the render pass would have closed either way.
ANGLE_TRY(contextVk->endRenderPass()); ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
} }
// If not a partial invalidate, mark the contents of the invalidated attachments as undefined, // If not a partial invalidate, mark the contents of the invalidated attachments as undefined,
...@@ -1656,7 +1646,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context, ...@@ -1656,7 +1646,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(), mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(),
mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any()); mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any());
ANGLE_TRY(contextVk->endRenderPass()); ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
// Notify the ContextVk to update the pipeline desc. // Notify the ContextVk to update the pipeline desc.
updateRenderPassDesc(); updateRenderPassDesc();
...@@ -1952,23 +1942,13 @@ VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL, ...@@ -1952,23 +1942,13 @@ VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL,
return clearValue; return clearValue;
} }
void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers, void FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
bool clearStencil, bool clearStencil,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue) const VkClearDepthStencilValue &clearDepthStencilValue)
{ {
// Go through clearColorBuffers and set the appropriate loadOp and clear values.
for (size_t colorIndexGL : clearColorBuffers)
{
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, VK_IMAGE_ASPECT_COLOR_BIT,
clearValue);
}
// Set the appropriate loadOp and clear values for depth and stencil. // Set the appropriate loadOp and clear values for depth and stencil.
VkImageAspectFlags dsAspectFlags = 0; VkImageAspectFlags dsAspectFlags = 0;
if (clearDepth) if (clearDepth)
...@@ -1981,6 +1961,45 @@ void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers, ...@@ -1981,6 +1961,45 @@ void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers,
dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
} }
if (contextVk->hasStartedRenderPass())
{
vk::CommandBufferHelper &commands = contextVk->getStartedRenderPassCommands();
ASSERT(commands.getCommandBuffer().empty());
// The clear colors are packed with no gaps. The draw buffers mask is unpacked
// and can have gaps. Thus we need to count the packed index explicitly in this loop.
size_t colorCount = 0;
for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
{
if (clearColorBuffers[colorIndexGL])
{
VkClearValue clearValue =
getCorrectedColorClearValue(colorIndexGL, clearColorValue);
commands.updateRenderPassColorClear(colorCount, clearValue);
}
colorCount++;
}
if (dsAspectFlags)
{
VkClearValue clearValue;
clearValue.depthStencil = clearDepthStencilValue;
commands.updateRenderPassDepthStencilClear(dsAspectFlags, clearValue);
}
}
else
{
for (size_t colorIndexGL : clearColorBuffers)
{
ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColorValue);
gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, VK_IMAGE_ASPECT_COLOR_BIT,
clearValue);
}
if (dsAspectFlags) if (dsAspectFlags)
{ {
RenderTargetVk *renderTarget = getDepthStencilRenderTarget(); RenderTargetVk *renderTarget = getDepthStencilRenderTarget();
...@@ -1992,9 +2011,10 @@ void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers, ...@@ -1992,9 +2011,10 @@ void FramebufferVk::clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers,
gl::ImageIndex imageIndex = renderTarget->getImageIndex(); gl::ImageIndex imageIndex = renderTarget->getImageIndex();
renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, clearValue); renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, clearValue);
} }
}
} }
void FramebufferVk::clearWithClearAttachment(vk::CommandBuffer *renderPassCommandBuffer, void FramebufferVk::clearWithCommand(vk::CommandBuffer *renderPassCommandBuffer,
const gl::Rectangle &scissoredRenderArea, const gl::Rectangle &scissoredRenderArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
...@@ -2056,7 +2076,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2056,7 +2076,7 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
vk::Framebuffer *framebuffer = nullptr; vk::Framebuffer *framebuffer = nullptr;
ANGLE_TRY(getFramebuffer(contextVk, &framebuffer)); ANGLE_TRY(getFramebuffer(contextVk, &framebuffer));
ANGLE_TRY(contextVk->endRenderPass()); ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
// Initialize RenderPass info. // Initialize RenderPass info.
vk::AttachmentOpsArray renderPassAttachmentOps; vk::AttachmentOpsArray renderPassAttachmentOps;
...@@ -2202,9 +2222,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2202,9 +2222,9 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
stencilStoreOp); stencilStoreOp);
} }
ANGLE_TRY(contextVk->flushAndBeginRenderPass( ANGLE_TRY(contextVk->beginNewRenderPass(*framebuffer, renderArea, mRenderPassDesc,
*framebuffer, renderArea, mRenderPassDesc, renderPassAttachmentOps, renderPassAttachmentOps, depthStencilAttachmentIndex,
depthStencilAttachmentIndex, packedClearValues, commandBufferOut)); packedClearValues, commandBufferOut));
// Transition the images to the correct layout (through onColorDraw) after the // Transition the images to the correct layout (through onColorDraw) after the
// resolve-to-multisampled copies are done. // resolve-to-multisampled copies are done.
......
...@@ -185,12 +185,13 @@ class FramebufferVk : public FramebufferImpl ...@@ -185,12 +185,13 @@ class FramebufferVk : public FramebufferImpl
uint8_t stencilMask, uint8_t stencilMask,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
void clearWithRenderPassOp(gl::DrawBufferMask clearColorBuffers, void clearWithLoadOp(ContextVk *contextVk,
gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
bool clearStencil, bool clearStencil,
const VkClearColorValue &clearColorValue, const VkClearColorValue &clearColorValue,
const VkClearDepthStencilValue &clearDepthStencilValue); const VkClearDepthStencilValue &clearDepthStencilValue);
void clearWithClearAttachment(vk::CommandBuffer *renderPassCommandBuffer, void clearWithCommand(vk::CommandBuffer *renderPassCommandBuffer,
const gl::Rectangle &scissoredRenderArea, const gl::Rectangle &scissoredRenderArea,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
bool clearDepth, bool clearDepth,
......
...@@ -986,7 +986,7 @@ void ProgramExecutableVk::updateBuffersDescriptorSet(ContextVk *contextVk, ...@@ -986,7 +986,7 @@ void ProgramExecutableVk::updateBuffersDescriptorSet(ContextVk *contextVk,
VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; VkAccessFlags accessFlags = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
commandBufferHelper->bufferWrite(resourceUseList, accessFlags, commandBufferHelper->bufferWrite(resourceUseList, accessFlags,
kPipelineStageShaderMap[shaderType], kPipelineStageShaderMap[shaderType],
vk::BufferAliasingMode::Allowed, &bufferHelper); vk::AliasingMode::Allowed, &bufferHelper);
} }
else else
{ {
...@@ -1056,7 +1056,7 @@ void ProgramExecutableVk::updateAtomicCounterBuffersDescriptorSet( ...@@ -1056,7 +1056,7 @@ void ProgramExecutableVk::updateAtomicCounterBuffersDescriptorSet(
// We set SHADER_READ_BIT to be conservative. // We set SHADER_READ_BIT to be conservative.
commandBufferHelper->bufferWrite( commandBufferHelper->bufferWrite(
resourceUseList, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, resourceUseList, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
kPipelineStageShaderMap[shaderType], vk::BufferAliasingMode::Allowed, &bufferHelper); kPipelineStageShaderMap[shaderType], vk::AliasingMode::Allowed, &bufferHelper);
writtenBindings.set(binding); writtenBindings.set(binding);
} }
......
...@@ -1126,9 +1126,9 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk, ...@@ -1126,9 +1126,9 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk,
renderPassAttachmentOps.initWithLoadStore(0, vk::ImageLayout::ColorAttachment, renderPassAttachmentOps.initWithLoadStore(0, vk::ImageLayout::ColorAttachment,
vk::ImageLayout::ColorAttachment); vk::ImageLayout::ColorAttachment);
ANGLE_TRY(contextVk->flushAndBeginRenderPass( ANGLE_TRY(contextVk->beginNewRenderPass(framebuffer, renderArea, renderPassDesc,
framebuffer, renderArea, renderPassDesc, renderPassAttachmentOps, renderPassAttachmentOps, vk::kInvalidAttachmentIndex,
vk::kInvalidAttachmentIndex, clearValues, commandBufferOut)); clearValues, commandBufferOut));
contextVk->addGarbage(&framebuffer); contextVk->addGarbage(&framebuffer);
...@@ -1853,7 +1853,7 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, ...@@ -1853,7 +1853,7 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
descriptorPoolBinding.reset(); descriptorPoolBinding.reset();
// Close the render pass for this temporary framebuffer. // Close the render pass for this temporary framebuffer.
ANGLE_TRY(contextVk->endRenderPass()); ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -1549,6 +1549,18 @@ void AttachmentOpsArray::setStencilOps(size_t index, ...@@ -1549,6 +1549,18 @@ void AttachmentOpsArray::setStencilOps(size_t index,
SetBitField(ops.stencilStoreOp, storeOp); SetBitField(ops.stencilStoreOp, storeOp);
} }
void AttachmentOpsArray::setClearOp(size_t index)
{
PackedAttachmentOpsDesc &ops = mOps[index];
SetBitField(ops.loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
}
void AttachmentOpsArray::setClearStencilOp(size_t index)
{
PackedAttachmentOpsDesc &ops = mOps[index];
SetBitField(ops.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
}
size_t AttachmentOpsArray::hash() const size_t AttachmentOpsArray::hash() const
{ {
return angle::ComputeGenericHash(mOps); return angle::ComputeGenericHash(mOps);
......
...@@ -182,6 +182,9 @@ class AttachmentOpsArray final ...@@ -182,6 +182,9 @@ class AttachmentOpsArray final
void setOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp); void setOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp);
void setStencilOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp); void setStencilOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp);
void setClearOp(size_t index);
void setClearStencilOp(size_t index);
size_t hash() const; size_t hash() const;
private: private:
...@@ -786,19 +789,28 @@ class PipelineHelper final : angle::NonCopyable ...@@ -786,19 +789,28 @@ class PipelineHelper final : angle::NonCopyable
ANGLE_INLINE PipelineHelper::PipelineHelper(Pipeline &&pipeline) : mPipeline(std::move(pipeline)) {} ANGLE_INLINE PipelineHelper::PipelineHelper(Pipeline &&pipeline) : mPipeline(std::move(pipeline)) {}
struct ImageViewSubresourceSerial struct ImageSubresourceRange
{ {
ImageViewSerial imageViewSerial;
uint16_t level : 10; // GL max is 1000 (fits in 10 bits). uint16_t level : 10; // GL max is 1000 (fits in 10 bits).
uint16_t levelCount : 6; // Max 63 levels (2 ** 6 - 1). If we need more, take from 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 layer : 15; // Implementation max is 2048 (11 bits).
uint16_t singleLayer : 1; // true/false only. Not possible to use sub-slices of levels. uint16_t singleLayer : 1; // true/false only. Not possible to use sub-slices of levels.
}; };
static_assert(sizeof(ImageSubresourceRange) == sizeof(uint32_t), "Size mismatch");
constexpr ImageSubresourceRange kInvalidImageSubresourceRange = {0, 0, 0, 0};
struct ImageViewSubresourceSerial
{
ImageViewSerial imageViewSerial;
ImageSubresourceRange subresource;
};
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 = {
0, 0, 0, 0}; kInvalidImageViewSerial, kInvalidImageSubresourceRange};
class TextureDescriptorDesc class TextureDescriptorDesc
{ {
......
...@@ -604,7 +604,7 @@ void CommandBufferHelper::bufferRead(ResourceUseList *resourceUseList, ...@@ -604,7 +604,7 @@ void CommandBufferHelper::bufferRead(ResourceUseList *resourceUseList,
void CommandBufferHelper::bufferWrite(ResourceUseList *resourceUseList, void CommandBufferHelper::bufferWrite(ResourceUseList *resourceUseList,
VkAccessFlags writeAccessType, VkAccessFlags writeAccessType,
PipelineStage writeStage, PipelineStage writeStage,
BufferAliasingMode aliasingMode, AliasingMode aliasingMode,
BufferHelper *buffer) BufferHelper *buffer)
{ {
buffer->retain(resourceUseList); buffer->retain(resourceUseList);
...@@ -618,7 +618,7 @@ void CommandBufferHelper::bufferWrite(ResourceUseList *resourceUseList, ...@@ -618,7 +618,7 @@ void CommandBufferHelper::bufferWrite(ResourceUseList *resourceUseList,
// We support aliasing by not tracking storage buffers. This works well with the GL API // We support aliasing by not tracking storage buffers. This works well with the GL API
// because storage buffers are required to be externally synchronized. // because storage buffers are required to be externally synchronized.
// Compute / XFB emulation buffers are not allowed to alias. // Compute / XFB emulation buffers are not allowed to alias.
if (aliasingMode == BufferAliasingMode::Disallowed) if (aliasingMode == AliasingMode::Disallowed)
{ {
ASSERT(!usesBuffer(*buffer)); ASSERT(!usesBuffer(*buffer));
mUsedBuffers.insert(buffer->getBufferSerial(), BufferAccess::Write); mUsedBuffers.insert(buffer->getBufferSerial(), BufferAccess::Write);
...@@ -641,11 +641,22 @@ void CommandBufferHelper::imageRead(ResourceUseList *resourceUseList, ...@@ -641,11 +641,22 @@ void CommandBufferHelper::imageRead(ResourceUseList *resourceUseList,
mPipelineBarrierMask.set(barrierIndex); mPipelineBarrierMask.set(barrierIndex);
} }
} }
if (mIsRenderPassCommandBuffer)
{
// As noted in the header we don't support multiple layouts reads for Images.
// We allow duplicate uses in the RP to accomodate for normal GL sampler usage.
if (!usesImageInRenderPass(*image))
{
mRenderPassUsedImages.insert(image->getImageSerial());
}
}
} }
void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList, void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList,
VkImageAspectFlags aspectFlags, VkImageAspectFlags aspectFlags,
ImageLayout imageLayout, ImageLayout imageLayout,
AliasingMode aliasingMode,
ImageHelper *image) ImageHelper *image)
{ {
image->retain(resourceUseList); image->retain(resourceUseList);
...@@ -658,6 +669,19 @@ void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList, ...@@ -658,6 +669,19 @@ void CommandBufferHelper::imageWrite(ResourceUseList *resourceUseList,
{ {
mPipelineBarrierMask.set(barrierIndex); mPipelineBarrierMask.set(barrierIndex);
} }
if (mIsRenderPassCommandBuffer)
{
// When used as a storage buffer we allow for aliased writes.
if (aliasingMode == AliasingMode::Disallowed)
{
ASSERT(!usesImageInRenderPass(*image));
}
if (!usesImageInRenderPass(*image))
{
mRenderPassUsedImages.insert(image->getImageSerial());
}
}
} }
void CommandBufferHelper::executeBarriers(PrimaryCommandBuffer *primary) void CommandBufferHelper::executeBarriers(PrimaryCommandBuffer *primary)
...@@ -928,11 +952,13 @@ void CommandBufferHelper::reset() ...@@ -928,11 +952,13 @@ void CommandBufferHelper::reset()
mDepthTestEverEnabled = false; mDepthTestEverEnabled = false;
mStencilTestEverEnabled = false; mStencilTestEverEnabled = false;
mDepthStencilAttachmentIndex = kInvalidAttachmentIndex; mDepthStencilAttachmentIndex = kInvalidAttachmentIndex;
mRenderPassUsedImages.clear();
} }
// This state should never change for non-renderPass command buffer // This state should never change for non-renderPass command buffer
ASSERT(mRenderPassStarted == false); ASSERT(mRenderPassStarted == false);
ASSERT(mValidTransformFeedbackBufferCount == 0); ASSERT(mValidTransformFeedbackBufferCount == 0);
ASSERT(mRebindTransformFeedbackBuffers == false); ASSERT(mRebindTransformFeedbackBuffers == false);
ASSERT(mRenderPassUsedImages.empty());
} }
void CommandBufferHelper::releaseToContextQueue(ContextVk *contextVk) void CommandBufferHelper::releaseToContextQueue(ContextVk *contextVk)
...@@ -969,6 +995,35 @@ void CommandBufferHelper::pauseTransformFeedbackIfStarted() ...@@ -969,6 +995,35 @@ void CommandBufferHelper::pauseTransformFeedbackIfStarted()
mTransformFeedbackCounterBuffers.data()); mTransformFeedbackCounterBuffers.data());
} }
void CommandBufferHelper::updateRenderPassColorClear(size_t colorIndex,
const VkClearValue &clearValue)
{
mAttachmentOps.setClearOp(colorIndex);
mClearValues.store(static_cast<uint32_t>(colorIndex), VK_IMAGE_ASPECT_COLOR_BIT, clearValue);
}
void CommandBufferHelper::updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue)
{
// Don't overwrite prior clear values for individual aspects.
VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
{
mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
}
if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
{
mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
}
// Bypass special D/S handling. This clear values array stores values packed.
mClearValues.storeNoDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
}
// DynamicBuffer implementation. // DynamicBuffer implementation.
DynamicBuffer::DynamicBuffer() DynamicBuffer::DynamicBuffer()
: mUsage(0), : mUsage(0),
...@@ -1766,6 +1821,11 @@ void QueryHelper::resetQueryPool(ContextVk *contextVk, ...@@ -1766,6 +1821,11 @@ void QueryHelper::resetQueryPool(ContextVk *contextVk,
angle::Result QueryHelper::beginQuery(ContextVk *contextVk) angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
{ {
if (contextVk->hasStartedRenderPass())
{
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}
CommandBuffer *outsideRenderPassCommandBuffer; CommandBuffer *outsideRenderPassCommandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer)); ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer));
const QueryPool &queryPool = getQueryPool(); const QueryPool &queryPool = getQueryPool();
...@@ -1777,6 +1837,11 @@ angle::Result QueryHelper::beginQuery(ContextVk *contextVk) ...@@ -1777,6 +1837,11 @@ angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
angle::Result QueryHelper::endQuery(ContextVk *contextVk) angle::Result QueryHelper::endQuery(ContextVk *contextVk)
{ {
if (contextVk->hasStartedRenderPass())
{
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}
CommandBuffer *outsideRenderPassCommandBuffer; CommandBuffer *outsideRenderPassCommandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer)); ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer));
outsideRenderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery); outsideRenderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery);
...@@ -1800,14 +1865,21 @@ void QueryHelper::endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderP ...@@ -1800,14 +1865,21 @@ void QueryHelper::endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderP
angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk) angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
{ {
if (contextVk->hasStartedRenderPass())
{
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}
CommandBuffer *outsideRenderPassCommandBuffer; CommandBuffer *outsideRenderPassCommandBuffer;
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer)); ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&outsideRenderPassCommandBuffer));
writeTimestamp(contextVk, outsideRenderPassCommandBuffer); writeTimestamp(contextVk, outsideRenderPassCommandBuffer);
return angle::Result::Continue; return angle::Result::Continue;
} }
void QueryHelper::writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary) void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
{ {
// Note that commands may not be flushed at this point.
const QueryPool &queryPool = getQueryPool(); const QueryPool &queryPool = getQueryPool();
primary->resetQueryPool(queryPool, mQuery, 1); primary->resetQueryPool(queryPool, mQuery, 1);
primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery); primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
...@@ -4550,11 +4622,6 @@ angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk, ...@@ -4550,11 +4622,6 @@ angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
ANGLE_TRY(allocateStagingMemory(contextVk, *bufferSize, outDataPtr, bufferOut, bufferOffsetsOut, ANGLE_TRY(allocateStagingMemory(contextVk, *bufferSize, outDataPtr, bufferOut, bufferOffsetsOut,
nullptr)); nullptr));
CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->onImageTransferRead(aspectFlags, this));
ANGLE_TRY(contextVk->onBufferTransferWrite(*bufferOut));
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&commandBuffer));
uint32_t sourceLevelVk = static_cast<uint32_t>(sourceLevelGL) - mBaseLevel; uint32_t sourceLevelVk = static_cast<uint32_t>(sourceLevelGL) - mBaseLevel;
VkBufferImageCopy regions[2] = {}; VkBufferImageCopy regions[2] = {};
...@@ -4603,10 +4670,14 @@ angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk, ...@@ -4603,10 +4670,14 @@ angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
regions[1].imageSubresource.baseArrayLayer = baseLayer; regions[1].imageSubresource.baseArrayLayer = baseLayer;
regions[1].imageSubresource.layerCount = layerCount; regions[1].imageSubresource.layerCount = layerCount;
regions[1].imageSubresource.mipLevel = sourceLevelVk; regions[1].imageSubresource.mipLevel = sourceLevelVk;
commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
(*bufferOut)->getBuffer().getHandle(), 1, &regions[1]);
} }
CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->onBufferTransferWrite(*bufferOut));
ANGLE_TRY(contextVk->onImageTransferRead(aspectFlags, this));
ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(&commandBuffer));
commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(), commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
(*bufferOut)->getBuffer().getHandle(), 1, regions); (*bufferOut)->getBuffer().getHandle(), 1, regions);
...@@ -5365,10 +5436,10 @@ ImageViewSubresourceSerial ImageViewHelper::getSubresourceSerial(uint32_t levelG ...@@ -5365,10 +5436,10 @@ ImageViewSubresourceSerial ImageViewHelper::getSubresourceSerial(uint32_t levelG
ImageViewSubresourceSerial serial; ImageViewSubresourceSerial serial;
serial.imageViewSerial = mImageViewSerial; serial.imageViewSerial = mImageViewSerial;
SetBitField(serial.level, levelGL); SetBitField(serial.subresource.level, levelGL);
SetBitField(serial.levelCount, levelCount); SetBitField(serial.subresource.levelCount, levelCount);
SetBitField(serial.layer, layer); SetBitField(serial.subresource.layer, layer);
SetBitField(serial.singleLayer, layerMode == LayerMode::Single ? 1 : 0); SetBitField(serial.subresource.singleLayer, layerMode == LayerMode::Single ? 1 : 0);
return serial; return serial;
} }
......
...@@ -422,7 +422,7 @@ class QueryHelper final ...@@ -422,7 +422,7 @@ class QueryHelper final
angle::Result flushAndWriteTimestamp(ContextVk *contextVk); angle::Result flushAndWriteTimestamp(ContextVk *contextVk);
// When syncing gpu/cpu time, main thread accesses primary directly // When syncing gpu/cpu time, main thread accesses primary directly
void writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary); void writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary);
// All other timestamp accesses should be made on outsideRenderPassCommandBuffer // All other timestamp accesses should be made on outsideRenderPassCommandBuffer
void writeTimestamp(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer); void writeTimestamp(ContextVk *contextVk, CommandBuffer *outsideRenderPassCommandBuffer);
...@@ -837,7 +837,7 @@ enum class BufferAccess ...@@ -837,7 +837,7 @@ enum class BufferAccess
Write, Write,
}; };
enum class BufferAliasingMode enum class AliasingMode
{ {
Allowed, Allowed,
Disallowed, Disallowed,
...@@ -851,7 +851,7 @@ enum class BufferAliasingMode ...@@ -851,7 +851,7 @@ enum class BufferAliasingMode
// into the CBH and then pass the CBH off to a worker thread that will // into the CBH and then pass the CBH off to a worker thread that will
// process the commands into a primary command buffer and then submit // process the commands into a primary command buffer and then submit
// those commands to the queue. // those commands to the queue.
struct CommandBufferHelper : angle::NonCopyable class CommandBufferHelper : angle::NonCopyable
{ {
public: public:
CommandBufferHelper(); CommandBufferHelper();
...@@ -867,17 +867,17 @@ struct CommandBufferHelper : angle::NonCopyable ...@@ -867,17 +867,17 @@ struct CommandBufferHelper : angle::NonCopyable
void bufferWrite(ResourceUseList *resourceUseList, void bufferWrite(ResourceUseList *resourceUseList,
VkAccessFlags writeAccessType, VkAccessFlags writeAccessType,
PipelineStage writeStage, PipelineStage writeStage,
BufferAliasingMode aliasingMode, AliasingMode aliasingMode,
BufferHelper *buffer); BufferHelper *buffer);
void imageRead(ResourceUseList *resourceUseList, void imageRead(ResourceUseList *resourceUseList,
VkImageAspectFlags aspectFlags, VkImageAspectFlags aspectFlags,
ImageLayout imageLayout, ImageLayout imageLayout,
ImageHelper *image); ImageHelper *image);
void imageWrite(ResourceUseList *resourceUseList, void imageWrite(ResourceUseList *resourceUseList,
VkImageAspectFlags aspectFlags, VkImageAspectFlags aspectFlags,
ImageLayout imageLayout, ImageLayout imageLayout,
AliasingMode aliasingMode,
ImageHelper *image); ImageHelper *image);
CommandBuffer &getCommandBuffer() { return mCommandBuffer; } CommandBuffer &getCommandBuffer() { return mCommandBuffer; }
...@@ -946,6 +946,10 @@ struct CommandBufferHelper : angle::NonCopyable ...@@ -946,6 +946,10 @@ struct CommandBufferHelper : angle::NonCopyable
SetBitField(mAttachmentOps[attachmentIndex].finalLayout, finalLayout); SetBitField(mAttachmentOps[attachmentIndex].finalLayout, finalLayout);
} }
void updateRenderPassColorClear(size_t colorIndex, const VkClearValue &colorClearValue);
void updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue);
const gl::Rectangle &getRenderArea() const const gl::Rectangle &getRenderArea() const
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
...@@ -971,6 +975,7 @@ struct CommandBufferHelper : angle::NonCopyable ...@@ -971,6 +975,7 @@ struct CommandBufferHelper : angle::NonCopyable
bool usesBuffer(const BufferHelper &buffer) const; bool usesBuffer(const BufferHelper &buffer) const;
bool usesBufferForWrite(const BufferHelper &buffer) const; bool usesBufferForWrite(const BufferHelper &buffer) const;
bool usesImageInRenderPass(const ImageHelper &image) const;
// Dumping the command stream is disabled by default. // Dumping the command stream is disabled by default.
static constexpr bool kEnableCommandStreamDiagnostics = false; static constexpr bool kEnableCommandStreamDiagnostics = false;
...@@ -1011,8 +1016,11 @@ struct CommandBufferHelper : angle::NonCopyable ...@@ -1011,8 +1016,11 @@ struct CommandBufferHelper : angle::NonCopyable
uint32_t mDepthStencilAttachmentIndex; uint32_t mDepthStencilAttachmentIndex;
// Tracks resources used in the command buffer. // Tracks resources used in the command buffer.
static constexpr uint32_t kFastMapSize = 8; // For Buffers, we track the read/write access type so we can enable simuntaneous reads.
// Images have unique layouts unlike buffers therefore we don't support multi-read.
static constexpr uint32_t kFastMapSize = 16;
angle::FastUnorderedMap<BufferSerial, BufferAccess, kFastMapSize> mUsedBuffers; angle::FastUnorderedMap<BufferSerial, BufferAccess, kFastMapSize> mUsedBuffers;
angle::FastUnorderedSet<ImageSerial, kFastMapSize> mRenderPassUsedImages;
}; };
static constexpr uint32_t kInvalidAttachmentIndex = -1; static constexpr uint32_t kInvalidAttachmentIndex = -1;
...@@ -1963,6 +1971,12 @@ class ActiveHandleCounter final : angle::NonCopyable ...@@ -1963,6 +1971,12 @@ class ActiveHandleCounter final : angle::NonCopyable
angle::PackedEnumMap<HandleType, uint32_t> mActiveCounts; angle::PackedEnumMap<HandleType, uint32_t> mActiveCounts;
angle::PackedEnumMap<HandleType, uint32_t> mAllocatedCounts; angle::PackedEnumMap<HandleType, uint32_t> mAllocatedCounts;
}; };
ANGLE_INLINE bool CommandBufferHelper::usesImageInRenderPass(const ImageHelper &image) const
{
ASSERT(mIsRenderPassCommandBuffer);
return mRenderPassUsedImages.contains(image.getImageSerial());
}
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
......
...@@ -741,15 +741,20 @@ void ClearValuesArray::store(uint32_t index, ...@@ -741,15 +741,20 @@ void ClearValuesArray::store(uint32_t index,
// Ensure for packed DS we're writing to the depth index. // Ensure for packed DS we're writing to the depth index.
ASSERT(index == kClearValueDepthIndex || ASSERT(index == kClearValueDepthIndex ||
(index == kClearValueStencilIndex && aspectFlags == VK_IMAGE_ASPECT_STENCIL_BIT)); (index == kClearValueStencilIndex && aspectFlags == VK_IMAGE_ASPECT_STENCIL_BIT));
mValues[kClearValueStencilIndex] = clearValue;
mEnabled.set(kClearValueStencilIndex); storeNoDepthStencil(kClearValueStencilIndex, clearValue);
} }
if (aspectFlags != VK_IMAGE_ASPECT_STENCIL_BIT) if (aspectFlags != VK_IMAGE_ASPECT_STENCIL_BIT)
{ {
storeNoDepthStencil(index, clearValue);
}
}
void ClearValuesArray::storeNoDepthStencil(uint32_t index, const VkClearValue &clearValue)
{
mValues[index] = clearValue; mValues[index] = clearValue;
mEnabled.set(index); mEnabled.set(index);
}
} }
// ResourceSerialFactory implementation. // ResourceSerialFactory implementation.
......
...@@ -659,6 +659,7 @@ class ClearValuesArray final ...@@ -659,6 +659,7 @@ class ClearValuesArray final
ClearValuesArray &operator=(const ClearValuesArray &rhs); ClearValuesArray &operator=(const ClearValuesArray &rhs);
void store(uint32_t index, VkImageAspectFlags aspectFlags, const VkClearValue &clearValue); void store(uint32_t index, VkImageAspectFlags aspectFlags, const VkClearValue &clearValue);
void storeNoDepthStencil(uint32_t index, const VkClearValue &clearValue);
void reset(size_t index) void reset(size_t index)
{ {
......
...@@ -1382,7 +1382,7 @@ TEST_P(VertexAttributeTest, DisabledAttribArrays) ...@@ -1382,7 +1382,7 @@ TEST_P(VertexAttributeTest, DisabledAttribArrays)
drawQuad(program, "a_position", 0.5f); drawQuad(program, "a_position", 0.5f);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green) << "color index " << colorIndex;
glDeleteProgram(program); glDeleteProgram(program);
} }
......
...@@ -39,9 +39,6 @@ class VulkanPerformanceCounterTest : public ANGLETest ...@@ -39,9 +39,6 @@ class VulkanPerformanceCounterTest : public ANGLETest
// Tests that texture updates to unused textures don't break the RP. // Tests that texture updates to unused textures don't break the RP.
TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass) TEST_P(VulkanPerformanceCounterTest, NewTextureDoesNotBreakRenderPass)
{ {
// TODO(jmadill): Fix test. http://anglebug.com/4911
ANGLE_SKIP_TEST_IF(IsVulkan());
const rx::vk::PerfCounters &counters = hackANGLE(); const rx::vk::PerfCounters &counters = hackANGLE();
GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow}; GLColor kInitialData[4] = {GLColor::red, GLColor::blue, GLColor::green, GLColor::yellow};
......
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