Commit 959037e0 by Jamie Madill Committed by Commit Bot

Vulkan: Preserve RPs on XFB changes when possible.

Instead of unconditonally ending the RenderPass we keep a set of active XFB buffers in the ContextVk. This lets us re-use RPs when we don't write to the same buffer repeatedly. Reduces the RenderPass count in our Manhattan capture from 29->23. Bug: angleproject:4622 Change-Id: I28c2d4d3db1490e5d07be3c48d21fd2cc6ff85d6 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2196957Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 002fa6dc
...@@ -619,7 +619,8 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -619,7 +619,8 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mGpuEventTimestampOrigin(0), mGpuEventTimestampOrigin(0),
mPrimaryBufferCounter(0), mPrimaryBufferCounter(0),
mRenderPassCounter(0), mRenderPassCounter(0),
mContextPriority(renderer->getDriverPriority(GetContextPriority(state))) mContextPriority(renderer->getDriverPriority(GetContextPriority(state))),
mCurrentIndirectBuffer(nullptr)
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk"); ANGLE_TRACE_EVENT0("gpu.angle", "ContextVk::ContextVk");
memset(&mClearColorValue, 0, sizeof(mClearColorValue)); memset(&mClearColorValue, 0, sizeof(mClearColorValue));
...@@ -984,7 +985,7 @@ angle::Result ContextVk::setupIndexedDraw(const gl::Context *context, ...@@ -984,7 +985,7 @@ angle::Result ContextVk::setupIndexedDraw(const gl::Context *context,
if (indexType != mCurrentDrawElementsType) if (indexType != mCurrentDrawElementsType)
{ {
mCurrentDrawElementsType = indexType; mCurrentDrawElementsType = indexType;
setIndexBufferDirty(); ANGLE_TRY(onIndexBufferChange(nullptr));
} }
const gl::Buffer *elementArrayBuffer = mVertexArray->getState().getElementArrayBuffer(); const gl::Buffer *elementArrayBuffer = mVertexArray->getState().getElementArrayBuffer();
...@@ -1039,6 +1040,12 @@ angle::Result ContextVk::setupIndirectDraw(const gl::Context *context, ...@@ -1039,6 +1040,12 @@ angle::Result ContextVk::setupIndirectDraw(const gl::Context *context,
GLsizei vertexCount = 0; GLsizei vertexCount = 0;
GLsizei instanceCount = 1; GLsizei instanceCount = 1;
if (indirectBuffer != mCurrentIndirectBuffer)
{
ANGLE_TRY(endRenderPass());
mCurrentIndirectBuffer = indirectBuffer;
}
mRenderPassCommands->bufferRead(&mResourceUseList, VK_ACCESS_INDIRECT_COMMAND_READ_BIT, mRenderPassCommands->bufferRead(&mResourceUseList, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
vk::PipelineStage::DrawIndirect, indirectBuffer); vk::PipelineStage::DrawIndirect, indirectBuffer);
...@@ -1061,7 +1068,7 @@ angle::Result ContextVk::setupIndexedIndirectDraw(const gl::Context *context, ...@@ -1061,7 +1068,7 @@ angle::Result ContextVk::setupIndexedIndirectDraw(const gl::Context *context,
if (indexType != mCurrentDrawElementsType) if (indexType != mCurrentDrawElementsType)
{ {
mCurrentDrawElementsType = indexType; mCurrentDrawElementsType = indexType;
setIndexBufferDirty(); ANGLE_TRY(onIndexBufferChange(nullptr));
} }
return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBuffer, return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBuffer,
...@@ -1092,7 +1099,7 @@ angle::Result ContextVk::setupLineLoopIndexedIndirectDraw(const gl::Context *con ...@@ -1092,7 +1099,7 @@ angle::Result ContextVk::setupLineLoopIndexedIndirectDraw(const gl::Context *con
if (indexType != mCurrentDrawElementsType) if (indexType != mCurrentDrawElementsType)
{ {
mCurrentDrawElementsType = indexType; mCurrentDrawElementsType = indexType;
setIndexBufferDirty(); ANGLE_TRY(onIndexBufferChange(nullptr));
} }
return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, dstIndirectBuf, return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, dstIndirectBuf,
...@@ -1120,7 +1127,7 @@ angle::Result ContextVk::setupLineLoopIndirectDraw(const gl::Context *context, ...@@ -1120,7 +1127,7 @@ angle::Result ContextVk::setupLineLoopIndirectDraw(const gl::Context *context,
if (gl::DrawElementsType::UnsignedInt != mCurrentDrawElementsType) if (gl::DrawElementsType::UnsignedInt != mCurrentDrawElementsType)
{ {
mCurrentDrawElementsType = gl::DrawElementsType::UnsignedInt; mCurrentDrawElementsType = gl::DrawElementsType::UnsignedInt;
setIndexBufferDirty(); ANGLE_TRY(onIndexBufferChange(nullptr));
} }
return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBufferHelperOut, return setupIndirectDraw(context, mode, mIndexedDirtyBitsMask, indirectBufferHelperOut,
...@@ -1138,7 +1145,7 @@ angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context, ...@@ -1138,7 +1145,7 @@ angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
{ {
ANGLE_TRY(mVertexArray->handleLineLoop(this, firstVertex, vertexOrIndexCount, ANGLE_TRY(mVertexArray->handleLineLoop(this, firstVertex, vertexOrIndexCount,
indexTypeOrInvalid, indices, numIndicesOut)); indexTypeOrInvalid, indices, numIndicesOut));
setIndexBufferDirty(); ANGLE_TRY(onIndexBufferChange(nullptr));
mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum mCurrentDrawElementsType = indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum
? indexTypeOrInvalid ? indexTypeOrInvalid
: gl::DrawElementsType::UnsignedInt; : gl::DrawElementsType::UnsignedInt;
...@@ -1447,7 +1454,9 @@ angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension( ...@@ -1447,7 +1454,9 @@ angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension(
ASSERT(executable); ASSERT(executable);
if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive()) if (!executable->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
{
return angle::Result::Continue; return angle::Result::Continue;
}
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback()); TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
size_t bufferCount = executable->getTransformFeedbackBufferCount(); size_t bufferCount = executable->getTransformFeedbackBufferCount();
...@@ -2807,8 +2816,8 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -2807,8 +2816,8 @@ angle::Result ContextVk::syncState(const gl::Context *context,
{ {
mVertexArray = vk::GetImpl(glState.getVertexArray()); mVertexArray = vk::GetImpl(glState.getVertexArray());
invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask()); invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
mVertexArray->updateActiveAttribInfo(this); ANGLE_TRY(mVertexArray->updateActiveAttribInfo(this));
setIndexBufferDirty(); ANGLE_TRY(onIndexBufferChange(mVertexArray->getCurrentElementArrayBuffer()));
break; break;
} }
case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING: case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
...@@ -3160,7 +3169,7 @@ void ContextVk::invalidateCurrentTransformFeedbackBuffers() ...@@ -3160,7 +3169,7 @@ void ContextVk::invalidateCurrentTransformFeedbackBuffers()
{ {
mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS); mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
} }
if (getFeatures().emulateTransformFeedback.enabled) else if (getFeatures().emulateTransformFeedback.enabled)
{ {
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS); mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
} }
...@@ -3171,6 +3180,7 @@ void ContextVk::onTransformFeedbackStateChanged() ...@@ -3171,6 +3180,7 @@ void ContextVk::onTransformFeedbackStateChanged()
if (getFeatures().supportsTransformFeedbackExtension.enabled) if (getFeatures().supportsTransformFeedbackExtension.enabled)
{ {
mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_STATE); mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_STATE);
invalidateCurrentTransformFeedbackBuffers();
} }
else if (getFeatures().emulateTransformFeedback.enabled) else if (getFeatures().emulateTransformFeedback.enabled)
{ {
...@@ -3178,6 +3188,66 @@ void ContextVk::onTransformFeedbackStateChanged() ...@@ -3178,6 +3188,66 @@ void ContextVk::onTransformFeedbackStateChanged()
} }
} }
angle::Result ContextVk::onBeginTransformFeedback(
size_t bufferCount,
const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers)
{
onTransformFeedbackStateChanged();
for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
{
if (mCurrentTransformFeedbackBuffers.count(buffers[bufferIndex]) != 0)
{
ANGLE_TRY(endRenderPass());
break;
}
}
populateTransformFeedbackBufferSet(bufferCount, buffers);
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_RESUME);
}
return angle::Result::Continue;
}
void ContextVk::populateTransformFeedbackBufferSet(
size_t bufferCount,
const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers)
{
for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
{
mCurrentTransformFeedbackBuffers.insert(buffers[bufferIndex]);
}
}
void ContextVk::onEndTransformFeedback()
{
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
mRenderPassCommands->endTransformFeedback();
}
else if (getFeatures().emulateTransformFeedback.enabled)
{
onTransformFeedbackStateChanged();
}
}
angle::Result ContextVk::onPauseTransformFeedback()
{
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
return endRenderPass();
}
else if (getFeatures().emulateTransformFeedback.enabled)
{
onTransformFeedbackStateChanged();
}
return angle::Result::Continue;
}
void ContextVk::invalidateGraphicsDescriptorSet(uint32_t usedDescriptorSet) void ContextVk::invalidateGraphicsDescriptorSet(uint32_t usedDescriptorSet)
{ {
// UtilsVk currently only uses set 0 // UtilsVk currently only uses set 0
...@@ -3985,10 +4055,9 @@ angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex) ...@@ -3985,10 +4055,9 @@ angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex)
ASSERT(!defaultBuffer.isCoherent()); ASSERT(!defaultBuffer.isCoherent());
ANGLE_TRY(defaultBuffer.flush(this)); ANGLE_TRY(defaultBuffer.flush(this));
mVertexArray->updateDefaultAttrib(this, attribIndex, bufferHandle, return mVertexArray->updateDefaultAttrib(this, attribIndex, bufferHandle,
defaultBuffer.getCurrentBuffer(), defaultBuffer.getCurrentBuffer(),
static_cast<uint32_t>(offset)); static_cast<uint32_t>(offset));
return angle::Result::Continue;
} }
void ContextVk::waitForSwapchainImageIfNecessary() void ContextVk::waitForSwapchainImageIfNecessary()
...@@ -4172,6 +4241,22 @@ angle::Result ContextVk::endRenderPass() ...@@ -4172,6 +4241,22 @@ angle::Result ContextVk::endRenderPass()
ANGLE_TRY(mActiveQueryAnySamplesConservative->stashQueryHelper(this)); ANGLE_TRY(mActiveQueryAnySamplesConservative->stashQueryHelper(this));
} }
mCurrentTransformFeedbackBuffers.clear();
mCurrentIndirectBuffer = nullptr;
// Reset serials for XFB if active.
if (mState.isTransformFeedbackActiveUnpaused())
{
const gl::ProgramExecutable *executable = mState.getProgramExecutable();
ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
TransformFeedbackVk *transformFeedbackVk =
vk::GetImpl(mState.getCurrentTransformFeedback());
populateTransformFeedbackBufferSet(xfbBufferCount, transformFeedbackVk->getBufferHelpers());
}
onRenderPassFinished(); onRenderPassFinished();
if (mGpuEventsEnabled) if (mGpuEventsEnabled)
......
...@@ -298,31 +298,19 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -298,31 +298,19 @@ class ContextVk : public ContextImpl, public vk::Context
ANGLE_INLINE void invalidateVertexAndIndexBuffers() ANGLE_INLINE void invalidateVertexAndIndexBuffers()
{ {
// TODO: Make the pipeline invalidate more fine-grained. Only need to dirty here if PSO
// VtxInput state (stride, fmt, inputRate...) has changed. http://anglebug.com/3256
invalidateCurrentGraphicsPipeline(); invalidateCurrentGraphicsPipeline();
mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS); mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER); mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
} }
ANGLE_INLINE void invalidateVertexBuffers() angle::Result onVertexBufferChange(const vk::BufferHelper *vertexBuffer);
{
mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
}
ANGLE_INLINE void onVertexAttributeChange(size_t attribIndex, angle::Result onVertexAttributeChange(size_t attribIndex,
GLuint stride, GLuint stride,
GLuint divisor, GLuint divisor,
angle::FormatID format, angle::FormatID format,
GLuint relativeOffset) GLuint relativeOffset,
{ const vk::BufferHelper *vertexBuffer);
invalidateCurrentGraphicsPipeline();
mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
// Set divisor to 1 for attribs with emulated divisor
mGraphicsPipelineDesc->updateVertexInput(
&mGraphicsPipelineTransition, static_cast<uint32_t>(attribIndex), stride,
divisor > mRenderer->getMaxVertexAttribDivisor() ? 1 : divisor, format, relativeOffset);
}
void invalidateDefaultAttribute(size_t attribIndex); void invalidateDefaultAttribute(size_t attribIndex);
void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask); void invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask);
...@@ -331,6 +319,11 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -331,6 +319,11 @@ class ContextVk : public ContextImpl, public vk::Context
void invalidateCurrentTransformFeedbackBuffers(); void invalidateCurrentTransformFeedbackBuffers();
void onTransformFeedbackStateChanged(); void onTransformFeedbackStateChanged();
angle::Result onBeginTransformFeedback(
size_t bufferCount,
const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers);
void onEndTransformFeedback();
angle::Result onPauseTransformFeedback();
// When UtilsVk issues draw or dispatch calls, it binds descriptor sets that the context is not // When UtilsVk issues draw or dispatch calls, it binds descriptor sets that the context is not
// aware of. This function is called to make sure affected descriptor set bindings are dirtied // aware of. This function is called to make sure affected descriptor set bindings are dirtied
...@@ -361,11 +354,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -361,11 +354,7 @@ class ContextVk : public ContextImpl, public vk::Context
} }
const gl::ActiveTextureArray<TextureVk *> &getActiveImages() const { return mActiveImages; } const gl::ActiveTextureArray<TextureVk *> &getActiveImages() const { return mActiveImages; }
void setIndexBufferDirty() angle::Result onIndexBufferChange(const vk::BufferHelper *currentIndexBuffer);
{
mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mLastIndexBufferOffset = reinterpret_cast<const void *>(angle::DirtyPointer);
}
angle::Result flushImpl(const vk::Semaphore *semaphore); angle::Result flushImpl(const vk::Semaphore *semaphore);
angle::Result finishImpl(); angle::Result finishImpl();
...@@ -802,6 +791,12 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -802,6 +791,12 @@ 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 endRenderPassIfTransformFeedbackBuffer(const vk::BufferHelper *buffer);
void populateTransformFeedbackBufferSet(
size_t bufferCount,
const gl::TransformFeedbackBuffersArray<vk::BufferHelper *> &buffers);
std::array<DirtyBitHandler, DIRTY_BIT_MAX> mGraphicsDirtyBitHandlers; std::array<DirtyBitHandler, DIRTY_BIT_MAX> mGraphicsDirtyBitHandlers;
std::array<DirtyBitHandler, DIRTY_BIT_MAX> mComputeDirtyBitHandlers; std::array<DirtyBitHandler, DIRTY_BIT_MAX> mComputeDirtyBitHandlers;
...@@ -937,6 +932,9 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -937,6 +932,9 @@ class ContextVk : public ContextImpl, public vk::Context
// Function recycleCommandBuffer() is public above // Function recycleCommandBuffer() is public above
bool mHasPrimaryCommands; bool mHasPrimaryCommands;
// Transform feedback buffers.
std::unordered_set<const vk::BufferHelper *> mCurrentTransformFeedbackBuffers;
// Internal shader library. // Internal shader library.
vk::ShaderLibrary mShaderLibrary; vk::ShaderLibrary mShaderLibrary;
UtilsVk mUtils; UtilsVk mUtils;
...@@ -976,8 +974,50 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -976,8 +974,50 @@ class ContextVk : public ContextImpl, public vk::Context
egl::ContextPriority mContextPriority; egl::ContextPriority mContextPriority;
const vk::BufferHelper *mCurrentIndirectBuffer;
std::vector<std::string> mCommandBufferDiagnostics; std::vector<std::string> mCommandBufferDiagnostics;
}; };
ANGLE_INLINE angle::Result ContextVk::endRenderPassIfTransformFeedbackBuffer(
const vk::BufferHelper *buffer)
{
if (!buffer || mCurrentTransformFeedbackBuffers.count(buffer) == 0)
{
return angle::Result::Continue;
}
return endRenderPass();
}
ANGLE_INLINE angle::Result ContextVk::onIndexBufferChange(
const vk::BufferHelper *currentIndexBuffer)
{
mGraphicsDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mLastIndexBufferOffset = reinterpret_cast<const void *>(angle::DirtyPointer);
return endRenderPassIfTransformFeedbackBuffer(currentIndexBuffer);
}
ANGLE_INLINE angle::Result ContextVk::onVertexBufferChange(const vk::BufferHelper *vertexBuffer)
{
mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
return endRenderPassIfTransformFeedbackBuffer(vertexBuffer);
}
ANGLE_INLINE angle::Result ContextVk::onVertexAttributeChange(size_t attribIndex,
GLuint stride,
GLuint divisor,
angle::FormatID format,
GLuint relativeOffset,
const vk::BufferHelper *vertexBuffer)
{
invalidateCurrentGraphicsPipeline();
// Set divisor to 1 for attribs with emulated divisor
mGraphicsPipelineDesc->updateVertexInput(
&mGraphicsPipelineTransition, static_cast<uint32_t>(attribIndex), stride,
divisor > mRenderer->getMaxVertexAttribDivisor() ? 1 : divisor, format, relativeOffset);
return onVertexBufferChange(vertexBuffer);
}
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_ #endif // LIBANGLE_RENDERER_VULKAN_CONTEXTVK_H_
...@@ -292,12 +292,8 @@ angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *avail ...@@ -292,12 +292,8 @@ angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *avail
return angle::Result::Continue; return angle::Result::Continue;
} }
void QueryVk::onTransformFeedbackEnd(const gl::Context *context) void QueryVk::onTransformFeedbackEnd(GLsizeiptr primitivesDrawn)
{ {
gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); mTransformFeedbackPrimitivesDrawn += primitivesDrawn;
ASSERT(transformFeedback);
mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn();
} }
} // namespace rx } // namespace rx
...@@ -34,7 +34,7 @@ class QueryVk : public QueryImpl ...@@ -34,7 +34,7 @@ class QueryVk : public QueryImpl
angle::Result getResult(const gl::Context *context, GLuint64 *params) override; angle::Result getResult(const gl::Context *context, GLuint64 *params) override;
angle::Result isResultAvailable(const gl::Context *context, bool *available) override; angle::Result isResultAvailable(const gl::Context *context, bool *available) override;
void onTransformFeedbackEnd(const gl::Context *context); void onTransformFeedbackEnd(GLsizeiptr primitivesDrawn);
vk::QueryHelper *getQueryHelper() { return &mQueryHelper; } vk::QueryHelper *getQueryHelper() { return &mQueryHelper; }
angle::Result stashQueryHelper(ContextVk *contextVk); angle::Result stashQueryHelper(ContextVk *contextVk);
angle::Result retrieveStashedQueryResult(ContextVk *contextVk, uint64_t *result); angle::Result retrieveStashedQueryResult(ContextVk *contextVk, uint64_t *result);
......
...@@ -1673,7 +1673,7 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev ...@@ -1673,7 +1673,7 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev
mIndexTypeUint8Features.indexTypeUint8 == VK_TRUE); mIndexTypeUint8Features.indexTypeUint8 == VK_TRUE);
ANGLE_FEATURE_CONDITION(&mFeatures, emulateTransformFeedback, ANGLE_FEATURE_CONDITION(&mFeatures, emulateTransformFeedback,
(mFeatures.supportsTransformFeedbackExtension.enabled == VK_FALSE && (!mFeatures.supportsTransformFeedbackExtension.enabled &&
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics == VK_TRUE)); mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics == VK_TRUE));
ANGLE_FEATURE_CONDITION(&mFeatures, disableFifoPresentMode, IsLinux() && isIntel); ANGLE_FEATURE_CONDITION(&mFeatures, disableFifoPresentMode, IsLinux() && isIntel);
......
...@@ -51,8 +51,6 @@ angle::Result TransformFeedbackVk::begin(const gl::Context *context, ...@@ -51,8 +51,6 @@ angle::Result TransformFeedbackVk::begin(const gl::Context *context,
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
contextVk->onTransformFeedbackStateChanged();
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable(); const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
ASSERT(executable); ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount(); size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
...@@ -120,7 +118,7 @@ angle::Result TransformFeedbackVk::begin(const gl::Context *context, ...@@ -120,7 +118,7 @@ angle::Result TransformFeedbackVk::begin(const gl::Context *context,
mRebindTransformFeedbackBuffer = true; mRebindTransformFeedbackBuffer = true;
} }
return onTransformFeedbackStateChanged(contextVk); return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers);
} }
angle::Result TransformFeedbackVk::end(const gl::Context *context) angle::Result TransformFeedbackVk::end(const gl::Context *context)
...@@ -132,45 +130,27 @@ angle::Result TransformFeedbackVk::end(const gl::Context *context) ...@@ -132,45 +130,27 @@ angle::Result TransformFeedbackVk::end(const gl::Context *context)
if (transformFeedbackQuery) if (transformFeedbackQuery)
{ {
vk::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(context); vk::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(mState.getPrimitivesDrawn());
} }
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
contextVk->onTransformFeedbackStateChanged(); contextVk->onEndTransformFeedback();
return angle::Result::Continue;
return onTransformFeedbackStateChanged(contextVk);
} }
angle::Result TransformFeedbackVk::pause(const gl::Context *context) angle::Result TransformFeedbackVk::pause(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
return contextVk->onPauseTransformFeedback();
contextVk->onTransformFeedbackStateChanged();
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
// We need to end the RenderPass to perform transform feedback pause/resume
// becasue vkCmdBegin/EndTransformFeedback can be placed once per RenderPass.
ANGLE_TRY(onTransformFeedbackStateChanged(contextVk));
}
return angle::Result::Continue;
} }
angle::Result TransformFeedbackVk::resume(const gl::Context *context) angle::Result TransformFeedbackVk::resume(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
const gl::ProgramExecutable *executable = contextVk->getState().getProgramExecutable();
contextVk->onTransformFeedbackStateChanged(); ASSERT(executable);
size_t xfbBufferCount = executable->getTransformFeedbackBufferCount();
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled) return contextVk->onBeginTransformFeedback(xfbBufferCount, mBufferHelpers);
{
// We need to end the RenderPass to perform transform feedback pause/resume
// becasue vkCmdBegin/EndTransformFeedback can be placed once per RenderPass.
ANGLE_TRY(onTransformFeedbackStateChanged(contextVk));
}
return angle::Result::Continue;
} }
angle::Result TransformFeedbackVk::bindIndexedBuffer( angle::Result TransformFeedbackVk::bindIndexedBuffer(
...@@ -296,20 +276,6 @@ void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk, ...@@ -296,20 +276,6 @@ void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
} }
} }
angle::Result TransformFeedbackVk::onTransformFeedbackStateChanged(ContextVk *contextVk)
{
// Currently, we don't handle resources switching from read-only to writable and back correctly.
// In the case of transform feedback, the attached buffers can switch between being written by
// transform feedback and being read as a vertex array buffer. For now, we'll end the render
// pass every time transform feedback is started or ended to work around this issue temporarily.
//
// TODO(syoussefi): detect changes to buffer usage (e.g. as transform feedback output, vertex
// or index data etc) in the front end and notify the backend. A new node should be created
// only on such changes. http://anglebug.com/3205
ANGLE_TRY(contextVk->endRenderPass());
return angle::Result::Continue;
}
void TransformFeedbackVk::writeDescriptorSet(ContextVk *contextVk, void TransformFeedbackVk::writeDescriptorSet(ContextVk *contextVk,
size_t xfbBufferCount, size_t xfbBufferCount,
VkDescriptorBufferInfo *pBufferInfo, VkDescriptorBufferInfo *pBufferInfo,
......
...@@ -92,7 +92,6 @@ class TransformFeedbackVk : public TransformFeedbackImpl ...@@ -92,7 +92,6 @@ class TransformFeedbackVk : public TransformFeedbackImpl
} }
private: private:
angle::Result onTransformFeedbackStateChanged(ContextVk *contextVk);
void writeDescriptorSet(ContextVk *contextVk, void writeDescriptorSet(ContextVk *contextVk,
size_t xfbBufferCount, size_t xfbBufferCount,
VkDescriptorBufferInfo *pBufferInfo, VkDescriptorBufferInfo *pBufferInfo,
......
...@@ -458,7 +458,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, ...@@ -458,7 +458,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
mLineLoopBufferFirstIndex.reset(); mLineLoopBufferFirstIndex.reset();
mLineLoopBufferLastIndex.reset(); mLineLoopBufferLastIndex.reset();
contextVk->setIndexBufferDirty(); ANGLE_TRY(contextVk->onIndexBufferChange(mCurrentElementArrayBuffer));
mDirtyLineLoopTranslation = true; mDirtyLineLoopTranslation = true;
break; break;
} }
...@@ -466,7 +466,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, ...@@ -466,7 +466,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA: case gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER_DATA:
mLineLoopBufferFirstIndex.reset(); mLineLoopBufferFirstIndex.reset();
mLineLoopBufferLastIndex.reset(); mLineLoopBufferLastIndex.reset();
contextVk->setIndexBufferDirty(); ANGLE_TRY(contextVk->onIndexBufferChange(mCurrentElementArrayBuffer));
mDirtyLineLoopTranslation = true; mDirtyLineLoopTranslation = true;
break; break;
...@@ -517,7 +517,8 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, ...@@ -517,7 +517,8 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
#undef ANGLE_VERTEX_DIRTY_BINDING_FUNC #undef ANGLE_VERTEX_DIRTY_BINDING_FUNC
#undef ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC #undef ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC
ANGLE_INLINE void VertexArrayVk::setDefaultPackedInput(ContextVk *contextVk, size_t attribIndex) ANGLE_INLINE angle::Result VertexArrayVk::setDefaultPackedInput(ContextVk *contextVk,
size_t attribIndex)
{ {
const gl::State &glState = contextVk->getState(); const gl::State &glState = contextVk->getState();
const gl::VertexAttribCurrentValueData &defaultValue = const gl::VertexAttribCurrentValueData &defaultValue =
...@@ -525,10 +526,10 @@ ANGLE_INLINE void VertexArrayVk::setDefaultPackedInput(ContextVk *contextVk, siz ...@@ -525,10 +526,10 @@ ANGLE_INLINE void VertexArrayVk::setDefaultPackedInput(ContextVk *contextVk, siz
angle::FormatID format = GetCurrentValueFormatID(defaultValue.Type); angle::FormatID format = GetCurrentValueFormatID(defaultValue.Type);
contextVk->onVertexAttributeChange(attribIndex, 0, 0, format, 0); return contextVk->onVertexAttributeChange(attribIndex, 0, 0, format, 0, nullptr);
} }
void VertexArrayVk::updateActiveAttribInfo(ContextVk *contextVk) angle::Result VertexArrayVk::updateActiveAttribInfo(ContextVk *contextVk)
{ {
const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes(); const std::vector<gl::VertexAttribute> &attribs = mState.getVertexAttributes();
const std::vector<gl::VertexBinding> &bindings = mState.getVertexBindings(); const std::vector<gl::VertexBinding> &bindings = mState.getVertexBindings();
...@@ -539,10 +540,13 @@ void VertexArrayVk::updateActiveAttribInfo(ContextVk *contextVk) ...@@ -539,10 +540,13 @@ void VertexArrayVk::updateActiveAttribInfo(ContextVk *contextVk)
const gl::VertexAttribute &attrib = attribs[attribIndex]; const gl::VertexAttribute &attrib = attribs[attribIndex];
const gl::VertexBinding &binding = bindings[attribs[attribIndex].bindingIndex]; const gl::VertexBinding &binding = bindings[attribs[attribIndex].bindingIndex];
contextVk->onVertexAttributeChange(attribIndex, mCurrentArrayBufferStrides[attribIndex], ANGLE_TRY(contextVk->onVertexAttributeChange(
binding.getDivisor(), attrib.format->id, attribIndex, mCurrentArrayBufferStrides[attribIndex], binding.getDivisor(),
mCurrentArrayBufferRelativeOffsets[attribIndex]); attrib.format->id, mCurrentArrayBufferRelativeOffsets[attribIndex],
mCurrentArrayBuffers[attribIndex]));
} }
return angle::Result::Continue;
} }
angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
...@@ -649,13 +653,14 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, ...@@ -649,13 +653,14 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
if (bufferOnly) if (bufferOnly)
{ {
contextVk->invalidateVertexBuffers(); ANGLE_TRY(contextVk->onVertexBufferChange(mCurrentArrayBuffers[attribIndex]));
} }
else else
{ {
contextVk->onVertexAttributeChange(attribIndex, stride, binding.getDivisor(), ANGLE_TRY(contextVk->onVertexAttributeChange(
attrib.format->id, attribIndex, stride, binding.getDivisor(), attrib.format->id,
mCurrentArrayBufferRelativeOffsets[attribIndex]); mCurrentArrayBufferRelativeOffsets[attribIndex],
mCurrentArrayBuffers[attribIndex]));
// Cache the stride of the attribute // Cache the stride of the attribute
mCurrentArrayBufferStrides[attribIndex] = stride; mCurrentArrayBufferStrides[attribIndex] = stride;
} }
...@@ -678,7 +683,7 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, ...@@ -678,7 +683,7 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
mCurrentArrayBufferStrides[attribIndex] = 0; mCurrentArrayBufferStrides[attribIndex] = 0;
mCurrentArrayBufferRelativeOffsets[attribIndex] = 0; mCurrentArrayBufferRelativeOffsets[attribIndex] = 0;
setDefaultPackedInput(contextVk, attribIndex); ANGLE_TRY(setDefaultPackedInput(contextVk, attribIndex));
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -853,11 +858,11 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk, ...@@ -853,11 +858,11 @@ angle::Result VertexArrayVk::handleLineLoop(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
void VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk, angle::Result VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk,
size_t attribIndex, size_t attribIndex,
VkBuffer bufferHandle, VkBuffer bufferHandle,
vk::BufferHelper *buffer, vk::BufferHelper *buffer,
uint32_t offset) uint32_t offset)
{ {
if (!mState.getEnabledAttributesMask().test(attribIndex)) if (!mState.getEnabledAttributesMask().test(attribIndex))
{ {
...@@ -865,7 +870,9 @@ void VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk, ...@@ -865,7 +870,9 @@ void VertexArrayVk::updateDefaultAttrib(ContextVk *contextVk,
mCurrentArrayBufferOffsets[attribIndex] = offset; mCurrentArrayBufferOffsets[attribIndex] = offset;
mCurrentArrayBuffers[attribIndex] = buffer; mCurrentArrayBuffers[attribIndex] = buffer;
setDefaultPackedInput(contextVk, attribIndex); ANGLE_TRY(setDefaultPackedInput(contextVk, attribIndex));
} }
return angle::Result::Continue;
} }
} // namespace rx } // namespace rx
...@@ -32,13 +32,13 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -32,13 +32,13 @@ class VertexArrayVk : public VertexArrayImpl
gl::VertexArray::DirtyAttribBitsArray *attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
gl::VertexArray::DirtyBindingBitsArray *bindingBits) override; gl::VertexArray::DirtyBindingBitsArray *bindingBits) override;
void updateActiveAttribInfo(ContextVk *contextVk); angle::Result updateActiveAttribInfo(ContextVk *contextVk);
void updateDefaultAttrib(ContextVk *contextVk, angle::Result updateDefaultAttrib(ContextVk *contextVk,
size_t attribIndex, size_t attribIndex,
VkBuffer bufferHandle, VkBuffer bufferHandle,
vk::BufferHelper *buffer, vk::BufferHelper *buffer,
uint32_t offset); uint32_t offset);
angle::Result updateStreamedAttribs(const gl::Context *context, angle::Result updateStreamedAttribs(const gl::Context *context,
GLint firstVertex, GLint firstVertex,
...@@ -115,7 +115,7 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -115,7 +115,7 @@ class VertexArrayVk : public VertexArrayImpl
} }
private: private:
void setDefaultPackedInput(ContextVk *contextVk, size_t attribIndex); angle::Result setDefaultPackedInput(ContextVk *contextVk, size_t attribIndex);
angle::Result convertVertexBufferGPU(ContextVk *contextVk, angle::Result convertVertexBufferGPU(ContextVk *contextVk,
BufferVk *srcBuffer, BufferVk *srcBuffer,
......
...@@ -667,6 +667,13 @@ void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount, ...@@ -667,6 +667,13 @@ void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
} }
} }
void CommandBufferHelper::endTransformFeedback()
{
ASSERT(mIsRenderPassCommandBuffer);
pauseTransformFeedbackIfStarted();
mValidTransformFeedbackBufferCount = 0;
}
angle::Result CommandBufferHelper::flushToPrimary(ContextVk *contextVk, angle::Result CommandBufferHelper::flushToPrimary(ContextVk *contextVk,
vk::PrimaryCommandBuffer *primary) vk::PrimaryCommandBuffer *primary)
{ {
......
...@@ -882,6 +882,8 @@ struct CommandBufferHelper : angle::NonCopyable ...@@ -882,6 +882,8 @@ struct CommandBufferHelper : angle::NonCopyable
const VkBuffer *counterBuffers, const VkBuffer *counterBuffers,
bool rebindBuffers); bool rebindBuffers);
void endTransformFeedback();
void invalidateRenderPassColorAttachment(size_t attachmentIndex) void invalidateRenderPassColorAttachment(size_t attachmentIndex)
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
......
...@@ -79,6 +79,8 @@ class TransformFeedbackTest : public TransformFeedbackTestBase ...@@ -79,6 +79,8 @@ class TransformFeedbackTest : public TransformFeedbackTestBase
essl1_shaders::vs::Simple(), essl1_shaders::fs::Red(), tfVaryings, bufferMode); essl1_shaders::vs::Simple(), essl1_shaders::fs::Red(), tfVaryings, bufferMode);
ASSERT_NE(0u, mProgram); ASSERT_NE(0u, mProgram);
} }
void setupOverrunTest(const std::vector<GLfloat> &vertices);
}; };
TEST_P(TransformFeedbackTest, ZeroSizedViewport) TEST_P(TransformFeedbackTest, ZeroSizedViewport)
...@@ -1711,6 +1713,183 @@ TEST_P(TransformFeedbackTest, BufferOutOfMemory) ...@@ -1711,6 +1713,183 @@ TEST_P(TransformFeedbackTest, BufferOutOfMemory)
glEndTransformFeedback(); glEndTransformFeedback();
} }
void TransformFeedbackTest::setupOverrunTest(const std::vector<GLfloat> &vertices)
{
std::vector<uint8_t> zeroData(mTransformFeedbackBufferSize, 0);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBufferSize, zeroData.data());
// Draw a simple points XFB.
std::vector<std::string> tfVaryings;
tfVaryings.push_back("gl_Position");
compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
glUseProgram(mProgram);
GLint positionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
// First pass: draw 6 points to the XFB buffer
glEnable(GL_RASTERIZER_DISCARD);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, vertices.data());
glEnableVertexAttribArray(positionLocation);
// Bind the buffer for transform feedback output and start transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 6);
}
void VerifyVertexFloats(const GLfloat *mapPtrFloat,
const std::vector<GLfloat> &vertices,
size_t copies,
size_t numFloats)
{
for (size_t floatIndex = 0; floatIndex < vertices.size() * copies; ++floatIndex)
{
size_t vertIndex = floatIndex % vertices.size();
ASSERT_EQ(mapPtrFloat[floatIndex], vertices[vertIndex]) << "at float index " << floatIndex;
}
// The rest should be zero.
for (size_t floatIndex = vertices.size() * copies; floatIndex < numFloats; ++floatIndex)
{
ASSERT_EQ(mapPtrFloat[floatIndex], 0) << "at float index " << floatIndex;
}
}
// Tests that stopping XFB works as expected.
TEST_P(TransformFeedbackTest, Overrun)
{
const std::vector<GLfloat> vertices = {
-1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
-1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
};
setupOverrunTest(vertices);
glEndTransformFeedback();
// Draw a second time without XFB.
glDrawArrays(GL_POINTS, 0, 6);
ASSERT_GL_NO_ERROR();
// Verify only the first data was output.
const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
VerifyVertexFloats(mapPtrFloat, vertices, 1, numFloats);
}
// Similar to the overrun test but with Pause instead of End.
TEST_P(TransformFeedbackTest, OverrunWithPause)
{
const std::vector<GLfloat> vertices = {
-1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
-1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
};
setupOverrunTest(vertices);
glPauseTransformFeedback();
// Draw a second time without XFB.
glDrawArrays(GL_POINTS, 0, 6);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
// Verify only the first data was output.
const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
VerifyVertexFloats(mapPtrFloat, vertices, 1, numFloats);
}
// Similar to the overrun test but with Pause instead of End.
TEST_P(TransformFeedbackTest, OverrunWithPauseAndResume)
{
// Fails on Adreno Pixel 2 GL drivers. Not a supported configuration.
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAdreno() && IsAndroid());
// Fails on Windows Intel GL drivers. http://anglebug.com/4697
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
const std::vector<GLfloat> vertices = {
-1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
-1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
};
setupOverrunTest(vertices);
glPauseTransformFeedback();
// Draw a second time without XFB.
glDrawArrays(GL_POINTS, 0, 6);
// Draw a third time with XFB.
glResumeTransformFeedback();
glDrawArrays(GL_POINTS, 0, 6);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
// Verify only the first and third data was output.
const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
VerifyVertexFloats(mapPtrFloat, vertices, 2, numFloats);
}
// Similar to the overrun Pause/Resume test but with more than one Pause and Resume.
TEST_P(TransformFeedbackTest, OverrunWithMultiplePauseAndResume)
{
// Fails on Adreno Pixel 2 GL drivers. Not a supported configuration.
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsAdreno() && IsAndroid());
// Fails on Windows Intel GL drivers. http://anglebug.com/4697
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
const std::vector<GLfloat> vertices = {
-1.0f, 1.0f, 0.5f, 1.0f, -1.0f, -1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f,
-1.0f, 1.0f, 0.5f, 1.0f, 1.0f, -1.0f, 0.5f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
};
setupOverrunTest(vertices);
for (int iteration = 0; iteration < 2; ++iteration)
{
// Draw without XFB.
glPauseTransformFeedback();
glDrawArrays(GL_POINTS, 0, 6);
// Draw with XFB.
glResumeTransformFeedback();
glDrawArrays(GL_POINTS, 0, 6);
}
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
// Verify only the first and third data was output.
const void *mapPtr = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
mTransformFeedbackBufferSize, GL_MAP_READ_BIT);
const GLfloat *mapPtrFloat = reinterpret_cast<const float *>(mapPtr);
size_t numFloats = mTransformFeedbackBufferSize / sizeof(GLfloat);
VerifyVertexFloats(mapPtrFloat, vertices, 3, numFloats);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackTest); ANGLE_INSTANTIATE_TEST_ES3(TransformFeedbackTest);
......
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