Commit caa6eccd by Hyunchang Kim Committed by Commit Bot

Vulkan: Implement Transform Feedback support via extension

Implemented transform feedback extension path. Where VK_EXT_transform_feedback is supported, extension path will be taken over an emulation path. Extension path has advantages in terms of performance. BUG=angleproject:3206 Test: dEQP-GLES3.functional.transform_feedback.* angle_end2end_tests --gtest_filter=TransformFeedbackTest* Change-Id: Ia07c23afb289d9c67073469a97b714ec96f5265a Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1882767 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarMohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com>
parent ccea6b5b
...@@ -134,6 +134,13 @@ struct FeaturesVk : FeatureSetBase ...@@ -134,6 +134,13 @@ struct FeaturesVk : FeatureSetBase
"Emulate transform feedback as the VK_EXT_transform_feedback is not present.", &members, "Emulate transform feedback as the VK_EXT_transform_feedback is not present.", &members,
"http://anglebug.com/3205"}; "http://anglebug.com/3205"};
// Where VK_EXT_transform_feedback is supported, it's preferred over an emulation path.
// http://anglebug.com/3206
Feature supportsTransformFeedbackExtension = {
"supports_transform_feedback_extension", FeatureCategory::VulkanFeatures,
"Transform feedback uses the VK_EXT_transform_feedback extension.", &members,
"http://anglebug.com/3206"};
// VK_PRESENT_MODE_FIFO_KHR causes random timeouts on Linux Intel. http://anglebug.com/3153 // VK_PRESENT_MODE_FIFO_KHR causes random timeouts on Linux Intel. http://anglebug.com/3153
Feature disableFifoPresentMode = { Feature disableFifoPresentMode = {
"disable_fifo_present_mode", FeatureCategory::VulkanWorkarounds, "disable_fifo_present_mode", FeatureCategory::VulkanWorkarounds,
......
...@@ -207,6 +207,54 @@ size_t VariableExternalSize(GLenum type) ...@@ -207,6 +207,54 @@ size_t VariableExternalSize(GLenum type)
return VariableComponentSize(VariableComponentType(type)) * VariableComponentCount(type); return VariableComponentSize(VariableComponentType(type)) * VariableComponentCount(type);
} }
std::string GetGLSLTypeString(GLenum type)
{
switch (type)
{
case GL_BOOL:
return "bool";
case GL_INT:
return "int";
case GL_UNSIGNED_INT:
return "uint";
case GL_FLOAT:
return "float";
case GL_BOOL_VEC2:
return "bvec2";
case GL_BOOL_VEC3:
return "bvec3";
case GL_BOOL_VEC4:
return "bvec4";
case GL_INT_VEC2:
return "ivec2";
case GL_INT_VEC3:
return "ivec3";
case GL_INT_VEC4:
return "ivec4";
case GL_FLOAT_VEC2:
return "vec2";
case GL_FLOAT_VEC3:
return "vec3";
case GL_FLOAT_VEC4:
return "vec4";
case GL_UNSIGNED_INT_VEC2:
return "uvec2";
case GL_UNSIGNED_INT_VEC3:
return "uvec3";
case GL_UNSIGNED_INT_VEC4:
return "uvec4";
case GL_FLOAT_MAT2:
return "mat2";
case GL_FLOAT_MAT3:
return "mat3";
case GL_FLOAT_MAT4:
return "mat4";
default:
UNREACHABLE();
return nullptr;
}
}
GLenum VariableBoolVectorType(GLenum type) GLenum VariableBoolVectorType(GLenum type)
{ {
switch (type) switch (type)
......
...@@ -50,6 +50,7 @@ int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix); ...@@ -50,6 +50,7 @@ int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix);
int MatrixComponentCount(GLenum type, bool isRowMajorMatrix); int MatrixComponentCount(GLenum type, bool isRowMajorMatrix);
int VariableSortOrder(GLenum type); int VariableSortOrder(GLenum type);
GLenum VariableBoolVectorType(GLenum type); GLenum VariableBoolVectorType(GLenum type);
std::string GetGLSLTypeString(GLenum type);
int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize); int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
......
...@@ -108,6 +108,11 @@ void TransformFeedback::onDestroy(const Context *context) ...@@ -108,6 +108,11 @@ void TransformFeedback::onDestroy(const Context *context)
{ {
mState.mIndexedBuffers[i].set(context, nullptr, 0, 0); mState.mIndexedBuffers[i].set(context, nullptr, 0, 0);
} }
if (mImplementation)
{
mImplementation->onDestroy(context);
}
} }
TransformFeedback::~TransformFeedback() TransformFeedback::~TransformFeedback()
......
...@@ -284,11 +284,16 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -284,11 +284,16 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
{ {
std::set<std::string> uniqueFullNames; std::set<std::string> uniqueFullNames;
mPackedVaryings.clear(); mPackedVaryings.clear();
mInputVaryings.clear();
for (const auto &ref : mergedVaryings) for (const auto &ref : mergedVaryings)
{ {
const sh::ShaderVariable *input = ref.second.frontShader; const sh::ShaderVariable *input = ref.second.frontShader;
const sh::ShaderVariable *output = ref.second.backShader; const sh::ShaderVariable *output = ref.second.backShader;
if (input)
{
mInputVaryings.emplace_back(*input);
}
// Only pack statically used varyings that have a matched input or output, plus special // Only pack statically used varyings that have a matched input or output, plus special
// builtins. Note that we pack all statically used user-defined varyings even if they are // builtins. Note that we pack all statically used user-defined varyings even if they are
......
...@@ -182,6 +182,8 @@ class VaryingPacking final : angle::NonCopyable ...@@ -182,6 +182,8 @@ class VaryingPacking final : angle::NonCopyable
return mInactiveVaryingNames; return mInactiveVaryingNames;
} }
const std::vector<sh::ShaderVariable> &getInputVaryings() const { return mInputVaryings; }
private: private:
bool packVarying(const PackedVarying &packedVarying); bool packVarying(const PackedVarying &packedVarying);
bool isFree(unsigned int registerRow, bool isFree(unsigned int registerRow,
...@@ -194,6 +196,7 @@ class VaryingPacking final : angle::NonCopyable ...@@ -194,6 +196,7 @@ class VaryingPacking final : angle::NonCopyable
std::vector<Register> mRegisterMap; std::vector<Register> mRegisterMap;
std::vector<PackedVaryingRegister> mRegisterList; std::vector<PackedVaryingRegister> mRegisterList;
std::vector<sh::ShaderVariable> mInputVaryings;
std::vector<PackedVarying> mPackedVaryings; std::vector<PackedVarying> mPackedVaryings;
std::vector<std::string> mInactiveVaryingNames; std::vector<std::string> mInactiveVaryingNames;
......
...@@ -20,6 +20,7 @@ class TransformFeedbackImpl : angle::NonCopyable ...@@ -20,6 +20,7 @@ class TransformFeedbackImpl : angle::NonCopyable
public: public:
TransformFeedbackImpl(const gl::TransformFeedbackState &state) : mState(state) {} TransformFeedbackImpl(const gl::TransformFeedbackState &state) : mState(state) {}
virtual ~TransformFeedbackImpl() {} virtual ~TransformFeedbackImpl() {}
virtual void onDestroy(const gl::Context *context) {}
virtual angle::Result begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) = 0; virtual angle::Result begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) = 0;
virtual angle::Result end(const gl::Context *context) = 0; virtual angle::Result end(const gl::Context *context) = 0;
......
...@@ -47,6 +47,8 @@ std::string GlslangGetMappedSamplerName(const std::string &originalName); ...@@ -47,6 +47,8 @@ std::string GlslangGetMappedSamplerName(const std::string &originalName);
// resources (textures, buffers, xfb, etc) // resources (textures, buffers, xfb, etc)
void GlslangGetShaderSource(const GlslangSourceOptions &options, void GlslangGetShaderSource(const GlslangSourceOptions &options,
bool useOldRewriteStructSamplers, bool useOldRewriteStructSamplers,
bool supportsTransformFeedbackExtension,
bool emulateTransformFeedback,
const gl::ProgramState &programState, const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut); gl::ShaderMap<std::string> *shaderSourcesOut);
......
...@@ -45,7 +45,7 @@ void GlslangGetShaderSource(const gl::ProgramState &programState, ...@@ -45,7 +45,7 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut) gl::ShaderMap<std::string> *shaderSourcesOut)
{ {
rx::GlslangGetShaderSource(CreateSourceOptions(), false, programState, resources, rx::GlslangGetShaderSource(CreateSourceOptions(), false, false, false, programState, resources,
shaderSourcesOut); shaderSourcesOut);
} }
......
...@@ -102,12 +102,17 @@ angle::Result BufferVk::setData(const gl::Context *context, ...@@ -102,12 +102,17 @@ angle::Result BufferVk::setData(const gl::Context *context,
// We could potentially use multiple backing buffers for different usages. // We could potentially use multiple backing buffers for different usages.
// For now keep a single buffer with all relevant usage flags. // For now keep a single buffer with all relevant usage flags.
const VkImageUsageFlags usageFlags = VkImageUsageFlags usageFlags =
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
usageFlags |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
VkBufferCreateInfo createInfo = {}; VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.flags = 0; createInfo.flags = 0;
......
...@@ -207,6 +207,53 @@ void ExecuteCommands(PrimaryCommandBuffer *primCmdBuffer, priv::CommandBuffer *s ...@@ -207,6 +207,53 @@ void ExecuteCommands(PrimaryCommandBuffer *primCmdBuffer, priv::CommandBuffer *s
} }
ANGLE_MAYBE_UNUSED ANGLE_MAYBE_UNUSED
void InsertBeginTransformFeedback(PrimaryCommandBuffer *primCmdBuffer,
priv::SecondaryCommandBuffer &commandBuffer,
uint32_t validBufferCount,
const VkBuffer *counterBuffers,
bool rebindBuffer)
{
gl::TransformFeedbackBuffersArray<VkDeviceSize> offsets = {0, 0, 0, 0};
uint32_t counterBufferSize = (rebindBuffer) ? 0 : validBufferCount;
vkCmdBeginTransformFeedbackEXT(primCmdBuffer->getHandle(), 0, counterBufferSize, counterBuffers,
offsets.data());
}
ANGLE_MAYBE_UNUSED
void InsertEndTransformFeedback(PrimaryCommandBuffer *primCmdBuffer,
priv::SecondaryCommandBuffer &commandBuffer,
uint32_t validBufferCount,
const VkBuffer *counterBuffers)
{
gl::TransformFeedbackBuffersArray<VkDeviceSize> offsets = {0, 0, 0, 0};
vkCmdEndTransformFeedbackEXT(primCmdBuffer->getHandle(), 0, validBufferCount, counterBuffers,
offsets.data());
}
ANGLE_MAYBE_UNUSED
void InsertCounterBufferPipelineBarrier(PrimaryCommandBuffer *primCmdBuffer,
priv::SecondaryCommandBuffer &commandBuffer,
const VkBuffer *counterBuffers)
{
VkBufferMemoryBarrier bufferBarrier = {};
bufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
bufferBarrier.pNext = nullptr;
bufferBarrier.srcAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
bufferBarrier.dstAccessMask = VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT;
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferBarrier.buffer = counterBuffers[0];
bufferBarrier.offset = 0;
bufferBarrier.size = VK_WHOLE_SIZE;
vkCmdPipelineBarrier(primCmdBuffer->getHandle(), VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 0u, nullptr, 1u, &bufferBarrier,
0u, nullptr);
}
ANGLE_MAYBE_UNUSED
std::string DumpCommands(const priv::SecondaryCommandBuffer &commandBuffer, const char *separator) std::string DumpCommands(const priv::SecondaryCommandBuffer &commandBuffer, const char *separator)
{ {
return commandBuffer.dumpCommands(separator); return commandBuffer.dumpCommands(separator);
...@@ -381,7 +428,8 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function, ...@@ -381,7 +428,8 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function,
mGlobalMemoryBarrierSrcAccess(0), mGlobalMemoryBarrierSrcAccess(0),
mGlobalMemoryBarrierDstAccess(0), mGlobalMemoryBarrierDstAccess(0),
mGlobalMemoryBarrierStages(0), mGlobalMemoryBarrierStages(0),
mRenderPassOwner(nullptr) mRenderPassOwner(nullptr),
mValidTransformFeedbackBufferCount(0)
{} {}
CommandGraphNode::~CommandGraphNode() CommandGraphNode::~CommandGraphNode()
...@@ -604,8 +652,26 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, ...@@ -604,8 +652,26 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
beginInfo.pClearValues = mRenderPassClearValues.data(); beginInfo.pClearValues = mRenderPassClearValues.data();
primaryCommandBuffer->beginRenderPass(beginInfo, kRenderPassContents); primaryCommandBuffer->beginRenderPass(beginInfo, kRenderPassContents);
ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands); if (mValidTransformFeedbackBufferCount == 0)
primaryCommandBuffer->endRenderPass(); {
ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands);
primaryCommandBuffer->endRenderPass();
}
else
{
InsertBeginTransformFeedback(primaryCommandBuffer, mInsideRenderPassCommands,
mValidTransformFeedbackBufferCount,
mTransformFeedbackCounterBuffers.data(),
mRebindTransformFeedbackBuffers);
ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands);
InsertEndTransformFeedback(primaryCommandBuffer, mInsideRenderPassCommands,
mValidTransformFeedbackBufferCount,
mTransformFeedbackCounterBuffers.data());
primaryCommandBuffer->endRenderPass();
InsertCounterBufferPipelineBarrier(primaryCommandBuffer,
mInsideRenderPassCommands,
mTransformFeedbackCounterBuffers.data());
}
} }
break; break;
......
...@@ -205,6 +205,19 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -205,6 +205,19 @@ class CommandGraphNode final : angle::NonCopyable
mGlobalMemoryBarrierStages |= stages; mGlobalMemoryBarrierStages |= stages;
} }
ANGLE_INLINE void setActiveTransformFeedbackInfo(size_t validBufferCount,
const VkBuffer *counterBuffers,
bool rebindBuffer)
{
mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
mRebindTransformFeedbackBuffers = rebindBuffer;
for (size_t index = 0; index < validBufferCount; index++)
{
mTransformFeedbackCounterBuffers[index] = counterBuffers[index];
}
}
// This can only be set for RenderPass nodes. Each RenderPass node can have at most one owner. // This can only be set for RenderPass nodes. Each RenderPass node can have at most one owner.
void setRenderPassOwner(RenderPassOwner *owner) void setRenderPassOwner(RenderPassOwner *owner)
{ {
...@@ -269,6 +282,11 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -269,6 +282,11 @@ class CommandGraphNode final : angle::NonCopyable
// Render pass command buffer notifications. // Render pass command buffer notifications.
RenderPassOwner *mRenderPassOwner; RenderPassOwner *mRenderPassOwner;
// Active transform feedback state
gl::TransformFeedbackBuffersArray<VkBuffer> mTransformFeedbackCounterBuffers;
uint32_t mValidTransformFeedbackBufferCount;
bool mRebindTransformFeedbackBuffers;
}; };
// Tracks how a resource is used in a command graph and in a VkQueue. The reference count indicates // Tracks how a resource is used in a command graph and in a VkQueue. The reference count indicates
...@@ -454,6 +472,11 @@ class CommandGraphResource : angle::NonCopyable ...@@ -454,6 +472,11 @@ class CommandGraphResource : angle::NonCopyable
// Store a deferred memory barrier. Will be recorded into a primary command buffer at submit. // Store a deferred memory barrier. Will be recorded into a primary command buffer at submit.
void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess, VkPipelineStageFlags stages); void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess, VkPipelineStageFlags stages);
// Sets active transform feedback information to current writing node.
void setActiveTransformFeedbackInfo(size_t validBufferCount,
const VkBuffer *counterBuffers,
bool rebindBuffer);
protected: protected:
explicit CommandGraphResource(CommandGraphResourceType resourceType); explicit CommandGraphResource(CommandGraphResourceType resourceType);
...@@ -721,6 +744,16 @@ ANGLE_INLINE void CommandGraphResource::addGlobalMemoryBarrier(VkFlags srcAccess ...@@ -721,6 +744,16 @@ ANGLE_INLINE void CommandGraphResource::addGlobalMemoryBarrier(VkFlags srcAccess
mCurrentWritingNode->addGlobalMemoryBarrier(srcAccess, dstAccess, stages); mCurrentWritingNode->addGlobalMemoryBarrier(srcAccess, dstAccess, stages);
} }
ANGLE_INLINE void CommandGraphResource::setActiveTransformFeedbackInfo(
size_t validBufferCount,
const VkBuffer *counterBuffers,
bool rebindBuffer)
{
ASSERT(mCurrentWritingNode);
mCurrentWritingNode->setActiveTransformFeedbackInfo(validBufferCount, counterBuffers,
rebindBuffer);
}
ANGLE_INLINE bool CommandGraphResource::hasChildlessWritingNode() const ANGLE_INLINE bool CommandGraphResource::hasChildlessWritingNode() const
{ {
// Note: currently, we don't have a resource that can issue both generic and special // Note: currently, we don't have a resource that can issue both generic and special
......
...@@ -539,7 +539,15 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -539,7 +539,15 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS); mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER); mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES); mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_SHADER_RESOURCES);
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS); if (getFeatures().supportsTransformFeedbackExtension.enabled ||
getFeatures().emulateTransformFeedback.enabled)
{
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
}
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_STATE);
}
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS); mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE); mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE);
...@@ -558,8 +566,19 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -558,8 +566,19 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
&ContextVk::handleDirtyGraphicsDriverUniforms; &ContextVk::handleDirtyGraphicsDriverUniforms;
mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] = mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
&ContextVk::handleDirtyGraphicsShaderResources; &ContextVk::handleDirtyGraphicsShaderResources;
mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] = if (getFeatures().supportsTransformFeedbackExtension.enabled)
&ContextVk::handleDirtyGraphicsTransformFeedbackBuffers; {
mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
&ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension;
mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_STATE] =
&ContextVk::handleDirtyGraphicsTransformFeedbackState;
}
else if (getFeatures().emulateTransformFeedback.enabled)
{
mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
&ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation;
}
mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
&ContextVk::handleDirtyGraphicsDescriptorSets; &ContextVk::handleDirtyGraphicsDescriptorSets;
...@@ -1170,7 +1189,7 @@ angle::Result ContextVk::handleDirtyComputeShaderResources(const gl::Context *co ...@@ -1170,7 +1189,7 @@ angle::Result ContextVk::handleDirtyComputeShaderResources(const gl::Context *co
return handleDirtyShaderResourcesImpl(context, commandBuffer, &mDispatcher); return handleDirtyShaderResourcesImpl(context, commandBuffer, &mDispatcher);
} }
angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffers( angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
const gl::Context *context, const gl::Context *context,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
...@@ -1182,6 +1201,66 @@ angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffers( ...@@ -1182,6 +1201,66 @@ angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffers(
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersExtension(
const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
if (!mProgram->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActive())
return angle::Result::Continue;
size_t bufferIndex = 0;
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
size_t bufferCount = mProgram->getState().getTransformFeedbackBufferCount();
gl::TransformFeedbackBuffersArray<VkBuffer> bufferHandles;
for (bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
{
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding =
mState.getCurrentTransformFeedback()->getIndexedBuffer(bufferIndex);
gl::Buffer *buffer = bufferBinding.get();
ASSERT(buffer != nullptr);
vk::BufferHelper &bufferHelper = vk::GetImpl(buffer)->getBuffer();
bufferHandles[bufferIndex] = bufferHelper.getBuffer().getHandle();
}
const TransformFeedbackBufferRange &xfbBufferRangeExtension =
transformFeedbackVk->getTransformFeedbackBufferRange();
commandBuffer->bindTransformFeedbackBuffers(bufferCount, bufferHandles.data(),
xfbBufferRangeExtension.offsets.data(),
xfbBufferRangeExtension.sizes.data());
vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
transformFeedbackVk->addFramebufferDependency(this, mProgram->getState(), framebuffer);
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackState(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
if (!mProgram->hasTransformFeedbackOutput() || !mState.isTransformFeedbackActiveUnpaused())
return angle::Result::Continue;
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(mState.getCurrentTransformFeedback());
// We should have same number of counter buffers as xfb buffers have
size_t bufferCount = mProgram->getState().getTransformFeedbackBufferCount();
const gl::TransformFeedbackBuffersArray<VkBuffer> &counterBufferHandles =
transformFeedbackVk->getCounterBufferHandles();
vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
bool rebindBuffer = transformFeedbackVk->getTransformFeedbackBufferRebindState();
framebuffer->setActiveTransformFeedbackInfo(bufferCount, counterBufferHandles.data(),
rebindBuffer);
transformFeedbackVk->unsetTransformFeedbackBufferRebindState();
return angle::Result::Continue;
}
ANGLE_INLINE angle::Result ContextVk::handleDirtyDescriptorSetsImpl( ANGLE_INLINE angle::Result ContextVk::handleDirtyDescriptorSetsImpl(
vk::CommandBuffer *commandBuffer, vk::CommandBuffer *commandBuffer,
VkPipelineBindPoint bindPoint, VkPipelineBindPoint bindPoint,
...@@ -2655,12 +2734,27 @@ void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk) ...@@ -2655,12 +2734,27 @@ void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk)
void ContextVk::invalidateCurrentTransformFeedbackBuffers() void ContextVk::invalidateCurrentTransformFeedbackBuffers()
{ {
mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS); mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS); if (getFeatures().emulateTransformFeedback.enabled)
{
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
} }
void ContextVk::onTransformFeedbackPauseResume() void ContextVk::invalidateCurrentTransformFeedbackState()
{ {
invalidateGraphicsDriverUniforms(); mGraphicsDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_STATE);
}
void ContextVk::onTransformFeedbackStateChanged()
{
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
invalidateCurrentTransformFeedbackState();
}
else if (getFeatures().emulateTransformFeedback.enabled)
{
invalidateGraphicsDriverUniforms();
}
} }
angle::Result ContextVk::dispatchCompute(const gl::Context *context, angle::Result ContextVk::dispatchCompute(const gl::Context *context,
......
...@@ -311,7 +311,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -311,7 +311,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; } void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; }
void invalidateCurrentTransformFeedbackBuffers(); void invalidateCurrentTransformFeedbackBuffers();
void onTransformFeedbackPauseResume(); void invalidateCurrentTransformFeedbackState();
void onTransformFeedbackStateChanged();
vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType); vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType);
...@@ -433,6 +434,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -433,6 +434,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
DIRTY_BIT_DRIVER_UNIFORMS, DIRTY_BIT_DRIVER_UNIFORMS,
DIRTY_BIT_SHADER_RESOURCES, // excluding textures, which are handled separately. DIRTY_BIT_SHADER_RESOURCES, // excluding textures, which are handled separately.
DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS, DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
DIRTY_BIT_TRANSFORM_FEEDBACK_STATE,
DIRTY_BIT_DESCRIPTOR_SETS, DIRTY_BIT_DESCRIPTOR_SETS,
DIRTY_BIT_MAX, DIRTY_BIT_MAX,
}; };
...@@ -603,8 +605,14 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO ...@@ -603,8 +605,14 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsShaderResources(const gl::Context *context, angle::Result handleDirtyGraphicsShaderResources(const gl::Context *context,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsTransformFeedbackBuffers(const gl::Context *context, angle::Result handleDirtyGraphicsTransformFeedbackBuffersEmulation(
vk::CommandBuffer *commandBuffer); const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsTransformFeedbackBuffersExtension(
const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsTransformFeedbackState(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsDescriptorSets(const gl::Context *context, angle::Result handleDirtyGraphicsDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
......
...@@ -35,13 +35,15 @@ GlslangSourceOptions CreateSourceOptions() ...@@ -35,13 +35,15 @@ GlslangSourceOptions CreateSourceOptions()
} // namespace } // namespace
// static // static
void GlslangWrapperVk::GetShaderSource(bool useOldRewriteStructSamplers, void GlslangWrapperVk::GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState, const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut) gl::ShaderMap<std::string> *shaderSourcesOut)
{ {
GlslangGetShaderSource(CreateSourceOptions(), useOldRewriteStructSamplers, programState, GlslangGetShaderSource(CreateSourceOptions(), features.forceOldRewriteStructSamplers.enabled,
resources, shaderSourcesOut); features.supportsTransformFeedbackExtension.enabled,
features.emulateTransformFeedback.enabled, programState, resources,
shaderSourcesOut);
} }
// static // static
......
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
#include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/vulkan/vk_utils.h" #include "libANGLE/renderer/vulkan/vk_utils.h"
namespace angle
{
struct FeaturesVk;
} // namespace angle
namespace rx namespace rx
{ {
// This class currently holds no state. If we want to hold state we would need to solve the // This class currently holds no state. If we want to hold state we would need to solve the
...@@ -19,7 +24,7 @@ namespace rx ...@@ -19,7 +24,7 @@ namespace rx
class GlslangWrapperVk class GlslangWrapperVk
{ {
public: public:
static void GetShaderSource(bool useOldRewriteStructSamplers, static void GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState, const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources, const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut); gl::ShaderMap<std::string> *shaderSourcesOut);
......
...@@ -566,7 +566,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context, ...@@ -566,7 +566,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
// assignment done in that function. // assignment done in that function.
linkResources(resources); linkResources(resources);
GlslangWrapperVk::GetShaderSource(contextVk->useOldRewriteStructSamplers(), mState, resources, GlslangWrapperVk::GetShaderSource(contextVk->getRenderer()->getFeatures(), mState, resources,
&mShaderSources); &mShaderSources);
reset(contextVk); reset(contextVk);
...@@ -606,7 +606,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf ...@@ -606,7 +606,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
if (mState.hasLinkedShaderStage(gl::ShaderType::Vertex) && transformFeedback && if (mState.hasLinkedShaderStage(gl::ShaderType::Vertex) && transformFeedback &&
!mState.getLinkedTransformFeedbackVaryings().empty()) !mState.getLinkedTransformFeedbackVaryings().empty())
{ {
vk::GetImpl(transformFeedback)->updateDescriptorSetLayout(mState, &uniformsAndXfbSetDesc); TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(transformFeedback);
transformFeedbackVk->updateDescriptorSetLayout(contextVk, mState, &uniformsAndXfbSetDesc);
} }
ANGLE_TRY(renderer->getDescriptorSetLayout( ANGLE_TRY(renderer->getDescriptorSetLayout(
......
...@@ -1062,7 +1062,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1062,7 +1062,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
std::sort(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), StrLess); std::sort(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), StrLess);
ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionNames, enabledDeviceExtensions)); ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionNames, enabledDeviceExtensions));
// Select additional features to be enabled // Select additional features to be enabled.
VkPhysicalDeviceFeatures2KHR enabledFeatures = {}; VkPhysicalDeviceFeatures2KHR enabledFeatures = {};
enabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; enabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend; enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend;
...@@ -1073,6 +1073,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1073,6 +1073,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.fragmentStoresAndAtomics = enabledFeatures.features.fragmentStoresAndAtomics =
mPhysicalDeviceFeatures.fragmentStoresAndAtomics; mPhysicalDeviceFeatures.fragmentStoresAndAtomics;
enabledFeatures.features.geometryShader = mPhysicalDeviceFeatures.geometryShader; enabledFeatures.features.geometryShader = mPhysicalDeviceFeatures.geometryShader;
if (!vk::CommandBuffer::ExecutesInline()) if (!vk::CommandBuffer::ExecutesInline())
{ {
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries; enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
...@@ -1118,6 +1119,18 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1118,6 +1119,18 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties); vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
} }
bool supportsTransformFeedbackExt = getFeatures().supportsTransformFeedbackExtension.enabled;
if (supportsTransformFeedbackExt)
{
enabledDeviceExtensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);
VkPhysicalDeviceTransformFeedbackFeaturesEXT xfbFeature = {};
xfbFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;
xfbFeature.transformFeedback = true;
xfbFeature.geometryStreams = true;
vk::AppendToPNextChain(&enabledFeatures, &xfbFeature);
}
createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledDeviceExtensions.size());
createInfo.ppEnabledExtensionNames = createInfo.ppEnabledExtensionNames =
enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data(); enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
...@@ -1128,6 +1141,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1128,6 +1141,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
vkGetDeviceQueue(mDevice, mCurrentQueueFamilyIndex, 0, &mQueue); vkGetDeviceQueue(mDevice, mCurrentQueueFamilyIndex, 0, &mQueue);
if (supportsTransformFeedbackExt)
{
InitTransformFeedbackEXTFunctions(mDevice);
}
// Initialize the vulkan pipeline cache. // Initialize the vulkan pipeline cache.
bool success = false; bool success = false;
ANGLE_TRY(initPipelineCache(displayVk, &mPipelineCache, &success)); ANGLE_TRY(initPipelineCache(displayVk, &mPipelineCache, &success));
...@@ -1278,12 +1296,13 @@ gl::Version RendererVk::getMaxSupportedESVersion() const ...@@ -1278,12 +1296,13 @@ gl::Version RendererVk::getMaxSupportedESVersion() const
maxVersion = std::max(maxVersion, gl::Version(2, 0)); maxVersion = std::max(maxVersion, gl::Version(2, 0));
} }
// If vertexPipelineStoresAndAtomics is not supported, we can't currently support transform // If the Vulkan transform feedback extension is not present, we use an emulation path that
// feedback. TODO(syoussefi): this should be conditioned to the extension not being present as // requires the vertexPipelineStoresAndAtomics feature. Without the extension or this feature,
// well, when that code path is implemented. http://anglebug.com/3206 // we can't currently support transform feedback.
if (!mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics) if (!mFeatures.supportsTransformFeedbackExtension.enabled &&
!mFeatures.emulateTransformFeedback.enabled)
{ {
maxVersion = std::max(maxVersion, gl::Version(2, 0)); maxVersion = std::min(maxVersion, gl::Version(2, 0));
} }
// Limit to GLES 2.0 if maxPerStageDescriptorUniformBuffers is too low. // Limit to GLES 2.0 if maxPerStageDescriptorUniformBuffers is too low.
...@@ -1395,10 +1414,13 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames) ...@@ -1395,10 +1414,13 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
(&mFeatures), supportsShaderStencilExport, (&mFeatures), supportsShaderStencilExport,
ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames)); ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames));
// TODO(syoussefi): when the code path using the extension is implemented, this should be ANGLE_FEATURE_CONDITION(
// conditioned to the extension not being present as well. http://anglebug.com/3206 (&mFeatures), supportsTransformFeedbackExtension,
ExtensionFound(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, deviceExtensionNames));
ANGLE_FEATURE_CONDITION((&mFeatures), emulateTransformFeedback, ANGLE_FEATURE_CONDITION((&mFeatures), emulateTransformFeedback,
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics == VK_TRUE); (mFeatures.supportsTransformFeedbackExtension.enabled == VK_FALSE &&
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics == VK_TRUE));
ANGLE_FEATURE_CONDITION((&mFeatures), disableFifoPresentMode, IsLinux() && isIntel); ANGLE_FEATURE_CONDITION((&mFeatures), disableFifoPresentMode, IsLinux() && isIntel);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h" #include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h"
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx namespace rx
{ {
...@@ -75,6 +76,20 @@ void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer) ...@@ -75,6 +76,20 @@ void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer)
params->indexType); params->indexType);
break; break;
} }
case CommandID::BindTransformFeedbackBuffers:
{
const BindTransformFeedbackBuffersParams *params =
getParamPtr<BindTransformFeedbackBuffersParams>(currentCommand);
const VkBuffer *buffers =
Offset<VkBuffer>(params, sizeof(BindTransformFeedbackBuffersParams));
const VkDeviceSize *offsets =
Offset<VkDeviceSize>(buffers, sizeof(VkBuffer) * params->bindingCount);
const VkDeviceSize *sizes =
Offset<VkDeviceSize>(offsets, sizeof(VkDeviceSize) * params->bindingCount);
vkCmdBindTransformFeedbackBuffersEXT(cmdBuffer, 0, params->bindingCount,
buffers, offsets, sizes);
break;
}
case CommandID::BindVertexBuffers: case CommandID::BindVertexBuffers:
{ {
const BindVertexBuffersParams *params = const BindVertexBuffersParams *params =
...@@ -431,6 +446,9 @@ std::string SecondaryCommandBuffer::dumpCommands(const char *separator) const ...@@ -431,6 +446,9 @@ std::string SecondaryCommandBuffer::dumpCommands(const char *separator) const
case CommandID::BindVertexBuffers: case CommandID::BindVertexBuffers:
result += "BindVertexBuffers"; result += "BindVertexBuffers";
break; break;
case CommandID::BindTransformFeedbackBuffers:
result += "BindTransformFeedbackBuffers";
break;
case CommandID::BlitImage: case CommandID::BlitImage:
result += "BlitImage"; result += "BlitImage";
break; break;
......
...@@ -34,6 +34,7 @@ enum class CommandID : uint16_t ...@@ -34,6 +34,7 @@ enum class CommandID : uint16_t
BindDescriptorSets, BindDescriptorSets,
BindGraphicsPipeline, BindGraphicsPipeline,
BindIndexBuffer, BindIndexBuffer,
BindTransformFeedbackBuffers,
BindVertexBuffers, BindVertexBuffers,
BlitImage, BlitImage,
BufferBarrier, BufferBarrier,
...@@ -102,6 +103,13 @@ struct BindIndexBufferParams ...@@ -102,6 +103,13 @@ struct BindIndexBufferParams
}; };
VERIFY_4_BYTE_ALIGNMENT(BindIndexBufferParams) VERIFY_4_BYTE_ALIGNMENT(BindIndexBufferParams)
struct BindTransformFeedbackBuffersParams
{
// ANGLE always has firstBinding of 0 so not storing that currently
uint32_t bindingCount;
};
VERIFY_4_BYTE_ALIGNMENT(BindTransformFeedbackBuffersParams)
struct BindVertexBuffersParams struct BindVertexBuffersParams
{ {
// ANGLE always has firstBinding of 0 so not storing that currently // ANGLE always has firstBinding of 0 so not storing that currently
...@@ -443,6 +451,11 @@ class SecondaryCommandBuffer final : angle::NonCopyable ...@@ -443,6 +451,11 @@ class SecondaryCommandBuffer final : angle::NonCopyable
void bindIndexBuffer(const Buffer &buffer, VkDeviceSize offset, VkIndexType indexType); void bindIndexBuffer(const Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
void bindTransformFeedbackBuffers(size_t bindingCount,
const VkBuffer *buffers,
const VkDeviceSize *offsets,
const VkDeviceSize *sizes);
void bindVertexBuffers(uint32_t firstBinding, void bindVertexBuffers(uint32_t firstBinding,
uint32_t bindingCount, uint32_t bindingCount,
const VkBuffer *buffers, const VkBuffer *buffers,
...@@ -777,6 +790,26 @@ ANGLE_INLINE void SecondaryCommandBuffer::bindIndexBuffer(const Buffer &buffer, ...@@ -777,6 +790,26 @@ ANGLE_INLINE void SecondaryCommandBuffer::bindIndexBuffer(const Buffer &buffer,
paramStruct->indexType = indexType; paramStruct->indexType = indexType;
} }
ANGLE_INLINE void SecondaryCommandBuffer::bindTransformFeedbackBuffers(size_t bindingCount,
const VkBuffer *buffers,
const VkDeviceSize *offsets,
const VkDeviceSize *sizes)
{
uint8_t *writePtr;
size_t buffersSize = bindingCount * sizeof(VkBuffer);
size_t offsetsSize = bindingCount * sizeof(VkDeviceSize);
size_t sizesSize = offsetsSize;
BindTransformFeedbackBuffersParams *paramStruct =
initCommand<BindTransformFeedbackBuffersParams>(CommandID::BindTransformFeedbackBuffers,
buffersSize + offsetsSize + sizesSize,
&writePtr);
// Copy params
paramStruct->bindingCount = static_cast<uint32_t>(bindingCount);
writePtr = storePointerParameter(writePtr, buffers, buffersSize);
writePtr = storePointerParameter(writePtr, offsets, offsetsSize);
storePointerParameter(writePtr, sizes, sizesSize);
}
ANGLE_INLINE void SecondaryCommandBuffer::bindVertexBuffers(uint32_t firstBinding, ANGLE_INLINE void SecondaryCommandBuffer::bindVertexBuffers(uint32_t firstBinding,
uint32_t bindingCount, uint32_t bindingCount,
const VkBuffer *buffers, const VkBuffer *buffers,
......
...@@ -25,11 +25,24 @@ namespace vk ...@@ -25,11 +25,24 @@ namespace vk
class DescriptorSetLayoutDesc; class DescriptorSetLayoutDesc;
} }
// Cached buffer properties for faster descriptor set update and offset calculation.
struct TransformFeedbackBufferRange
{
// Offset as provided by OffsetBindingPointer.
gl::TransformFeedbackBuffersArray<VkDeviceSize> offsets;
// Size as provided by OffsetBindingPointer.
gl::TransformFeedbackBuffersArray<VkDeviceSize> sizes;
// Aligned offset usable for VkDescriptorBufferInfo. This value could be smaller than
// offset.
gl::TransformFeedbackBuffersArray<VkDeviceSize> alignedOffsets;
};
class TransformFeedbackVk : public TransformFeedbackImpl class TransformFeedbackVk : public TransformFeedbackImpl
{ {
public: public:
TransformFeedbackVk(const gl::TransformFeedbackState &state); TransformFeedbackVk(const gl::TransformFeedbackState &state);
~TransformFeedbackVk() override; ~TransformFeedbackVk() override;
void onDestroy(const gl::Context *context) override;
angle::Result begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) override; angle::Result begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) override;
angle::Result end(const gl::Context *context) override; angle::Result end(const gl::Context *context) override;
...@@ -40,7 +53,8 @@ class TransformFeedbackVk : public TransformFeedbackImpl ...@@ -40,7 +53,8 @@ class TransformFeedbackVk : public TransformFeedbackImpl
size_t index, size_t index,
const gl::OffsetBindingPointer<gl::Buffer> &binding) override; const gl::OffsetBindingPointer<gl::Buffer> &binding) override;
void updateDescriptorSetLayout(const gl::ProgramState &programState, void updateDescriptorSetLayout(ContextVk *contextVk,
const gl::ProgramState &programState,
vk::DescriptorSetLayoutDesc *descSetLayoutOut) const; vk::DescriptorSetLayoutDesc *descSetLayoutOut) const;
void addFramebufferDependency(ContextVk *contextVk, void addFramebufferDependency(ContextVk *contextVk,
const gl::ProgramState &programState, const gl::ProgramState &programState,
...@@ -58,25 +72,36 @@ class TransformFeedbackVk : public TransformFeedbackImpl ...@@ -58,25 +72,36 @@ class TransformFeedbackVk : public TransformFeedbackImpl
int32_t *offsetsOut, int32_t *offsetsOut,
size_t offsetsSize) const; size_t offsetsSize) const;
void unsetTransformFeedbackBufferRebindState() { mRebindTransformFeedbackBuffer = false; }
bool getTransformFeedbackBufferRebindState() const { return mRebindTransformFeedbackBuffer; }
const TransformFeedbackBufferRange &getTransformFeedbackBufferRange() const
{
return mTransformFeedbackBufferRange;
}
const gl::TransformFeedbackBuffersArray<VkBuffer> &getCounterBufferHandles() const
{
return mCounterBufferHandles;
}
private: private:
void onBeginOrEnd(const gl::Context *context); void onTransformFeedbackStateChanged(const gl::Context *context);
void writeDescriptorSet(ContextVk *contextVk, void writeDescriptorSet(ContextVk *contextVk,
size_t xfbBufferCount, size_t xfbBufferCount,
VkDescriptorBufferInfo *pBufferInfo, VkDescriptorBufferInfo *pBufferInfo,
VkDescriptorSet descSet) const; VkDescriptorSet descSet) const;
// Cached buffer properties for faster descriptor set update and offset calculation. // This member variable is set when glBindTransformFeedbackBuffers/glBeginTransformFeedback
struct BoundBufferRange // is called and unset in dirty bit handler for transform feedback state change. If this
{ // value is true, vertex shader will record transform feedback varyings from the beginning
// Offset as provided by OffsetBindingPointer. // of the buffer.
VkDeviceSize offset = 0; bool mRebindTransformFeedbackBuffer;
// Size as provided by OffsetBindingPointer. TransformFeedbackBufferRange mTransformFeedbackBufferRange;
VkDeviceSize size = 0; // Counter buffer used for pause and resume.
// Aligned offset usable for VkDescriptorBufferInfo. This value could be smaller than gl::TransformFeedbackBuffersArray<vk::BufferHelper> mCounterBuffer;
// offset. gl::TransformFeedbackBuffersArray<VkBuffer> mCounterBufferHandles;
VkDeviceSize alignedOffset = 0;
};
gl::TransformFeedbackBuffersArray<BoundBufferRange> mBoundBufferRanges;
}; };
} // namespace rx } // namespace rx
......
# Transform Feedback via extension
## Outline
ANGLE emulates transform feedback using the vertexPipelineStoresAndAtomics features in Vulkan.
But some GPU vendors do not support these atomics. Also the emulation becomes more difficult in
GLES 3.2. Therefore ANGLE must support using the VK_EXT_transform_feedback extension .
But some GPU vendor does not support this feature, So we need another implementation using
VK_EXT_transform_feedback.
We also expect a performance gain when we use this extension.
## Implementation of Pause/Resume using CounterBuffer
The Vulkan extension does not provide separate APIs for `glPauseTransformFeedback` /
`glEndTransformFeedback`.
Instead, Vulkan introduced Counter buffers in `vkCmdBeginTransformFeedbackEXT` /
`vkCmdEndTransformFeedbackEXT` as API parameters.
To pause, we call `vkCmdEndTransformFeedbackEXT` and provide valid buffer handles in the
`pCounterBuffers` array and valid offsets in the `pCounterBufferOffsets` array for the
implementation to save the resume points.
Then to resume, we call `vkCmdBeginTransformFeedbackEXT` with the previous `pCounterBuffers`
and `pCounterBufferOffsets` values.
Between the pause and resume there needs to be a memory barrier for the counter buffers with a
source access of `VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT` at pipeline stage
`VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT` to a destination access of
`VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT` at pipeline stage
`VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT`.
## Implementation of glTransformFeedbackVaryings
There is no equivalent function for glTransformFeedbackVaryings in Vulkan. The Vulkan specification
states that the last vertex processing stage shader must be declared with the XFB execution mode.
So we need to modify gl shader code to have transform feedback qualifiers. The glsl code will be
converted proper SPIR-V code.
we add the below layout qualifier for built-in XFB varyings.
```
out gl_PerVertex
{
layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride) varying_type varying_name;
}
```
And for user xfb varyings.
```
layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride, location = num )
out varying_type varying_name;
```
There are some corner cases we should handle.
If more than 2 built-in varyings are used in the shader, and only one varying is declared as a
transformFeedback varying, we can generate a layout qualifier like this.
```
out gl_PerVertex
{
layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride) varying_type varying_name1;
varying_type varying_name2;
...
}
```
ANGLE modifies gl_position.z in vertex shader for the Vulkan coordinate system. So, if we capture
the value of 'gl_position' in the XFB buffer, the captured values will be incorrect.
To resolve this, we declare user declare an internal position varying and copy the value from
'gl_position'. We capture the internal position varying during transform feedback operation.
```
layout(xfb_buffer = buffer_num, xfb_offset = offset, xfb_stride = stride, location = num )
out vec4 xfbANGLEPosition;
....
void main(){
...
xfbANGLEPosition = gl_Position;
(gl_Position.z = ((gl_Position.z + gl_Position.w) * 0.5));
}
```
...@@ -813,6 +813,13 @@ angle::Result GraphicsPipelineDesc::initializePipeline( ...@@ -813,6 +813,13 @@ angle::Result GraphicsPipelineDesc::initializePipeline(
*pNextPtr = &provokingVertexState; *pNextPtr = &provokingVertexState;
pNextPtr = &provokingVertexState.pNext; pNextPtr = &provokingVertexState.pNext;
} }
VkPipelineRasterizationStateStreamCreateInfoEXT rasterStreamState = {};
rasterStreamState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT;
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
rasterStreamState.rasterizationStream = 0;
rasterState.pNext = &rasterLineState;
}
// Multisample state. // Multisample state.
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
......
...@@ -563,43 +563,68 @@ PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR = nullpt ...@@ -563,43 +563,68 @@ PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR = nullpt
// VK_KHR_external_semaphore_fd // VK_KHR_external_semaphore_fd
PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr; PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR = nullptr;
// VK_EXT_transform_feedback
PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT = nullptr;
PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT = nullptr;
PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT = nullptr;
PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT = nullptr;
PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT = nullptr;
PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT = nullptr;
#if defined(ANGLE_PLATFORM_FUCHSIA) #if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface // VK_FUCHSIA_imagepipe_surface
PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr; PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
#endif #endif
#define GET_FUNC(vkName) \ #define GET_INSTANCE_FUNC(vkName) \
do \ do \
{ \ { \
vkName = reinterpret_cast<PFN_##vkName>(vkGetInstanceProcAddr(instance, #vkName)); \ vkName = reinterpret_cast<PFN_##vkName>(vkGetInstanceProcAddr(instance, #vkName)); \
ASSERT(vkName); \ ASSERT(vkName); \
} while (0) } while (0)
#define GET_DEVICE_FUNC(vkName) \
do \
{ \
vkName = reinterpret_cast<PFN_##vkName>(vkGetDeviceProcAddr(device, #vkName)); \
ASSERT(vkName); \
} while (0)
void InitDebugUtilsEXTFunctions(VkInstance instance) void InitDebugUtilsEXTFunctions(VkInstance instance)
{ {
GET_FUNC(vkCreateDebugUtilsMessengerEXT); GET_INSTANCE_FUNC(vkCreateDebugUtilsMessengerEXT);
GET_FUNC(vkDestroyDebugUtilsMessengerEXT); GET_INSTANCE_FUNC(vkDestroyDebugUtilsMessengerEXT);
GET_FUNC(vkCmdBeginDebugUtilsLabelEXT); GET_INSTANCE_FUNC(vkCmdBeginDebugUtilsLabelEXT);
GET_FUNC(vkCmdEndDebugUtilsLabelEXT); GET_INSTANCE_FUNC(vkCmdEndDebugUtilsLabelEXT);
GET_FUNC(vkCmdInsertDebugUtilsLabelEXT); GET_INSTANCE_FUNC(vkCmdInsertDebugUtilsLabelEXT);
} }
void InitDebugReportEXTFunctions(VkInstance instance) void InitDebugReportEXTFunctions(VkInstance instance)
{ {
GET_FUNC(vkCreateDebugReportCallbackEXT); GET_INSTANCE_FUNC(vkCreateDebugReportCallbackEXT);
GET_FUNC(vkDestroyDebugReportCallbackEXT); GET_INSTANCE_FUNC(vkDestroyDebugReportCallbackEXT);
} }
void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance) void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance)
{ {
GET_FUNC(vkGetPhysicalDeviceProperties2KHR); GET_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR);
GET_FUNC(vkGetPhysicalDeviceFeatures2KHR); GET_INSTANCE_FUNC(vkGetPhysicalDeviceFeatures2KHR);
}
void InitTransformFeedbackEXTFunctions(VkDevice device)
{
GET_DEVICE_FUNC(vkCmdBindTransformFeedbackBuffersEXT);
GET_DEVICE_FUNC(vkCmdBeginTransformFeedbackEXT);
GET_DEVICE_FUNC(vkCmdEndTransformFeedbackEXT);
GET_DEVICE_FUNC(vkCmdBeginQueryIndexedEXT);
GET_DEVICE_FUNC(vkCmdEndQueryIndexedEXT);
GET_DEVICE_FUNC(vkCmdDrawIndirectByteCountEXT);
} }
#if defined(ANGLE_PLATFORM_FUCHSIA) #if defined(ANGLE_PLATFORM_FUCHSIA)
void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance) void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance)
{ {
GET_FUNC(vkCreateImagePipeSurfaceFUCHSIA); GET_INSTANCE_FUNC(vkCreateImagePipeSurfaceFUCHSIA);
} }
#endif #endif
...@@ -609,8 +634,8 @@ PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferProper ...@@ -609,8 +634,8 @@ PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferProper
PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID = nullptr; PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID = nullptr;
void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance) void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance)
{ {
GET_FUNC(vkGetAndroidHardwareBufferPropertiesANDROID); GET_INSTANCE_FUNC(vkGetAndroidHardwareBufferPropertiesANDROID);
GET_FUNC(vkGetMemoryAndroidHardwareBufferANDROID); GET_INSTANCE_FUNC(vkGetMemoryAndroidHardwareBufferANDROID);
} }
#endif #endif
...@@ -625,10 +650,11 @@ void InitGGPStreamDescriptorSurfaceFunctions(VkInstance instance) ...@@ -625,10 +650,11 @@ void InitGGPStreamDescriptorSurfaceFunctions(VkInstance instance)
void InitExternalSemaphoreFdFunctions(VkInstance instance) void InitExternalSemaphoreFdFunctions(VkInstance instance)
{ {
GET_FUNC(vkImportSemaphoreFdKHR); GET_INSTANCE_FUNC(vkImportSemaphoreFdKHR);
} }
#undef GET_FUNC #undef GET_INSTANCE_FUNC
#undef GET_DEVICE_FUNC
namespace gl_vk namespace gl_vk
{ {
......
...@@ -625,10 +625,18 @@ extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; ...@@ -625,10 +625,18 @@ extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
// VK_KHR_external_semaphore_fd // VK_KHR_external_semaphore_fd
extern PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR; extern PFN_vkImportSemaphoreFdKHR vkImportSemaphoreFdKHR;
extern PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT;
extern PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT;
extern PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT;
extern PFN_vkCmdBeginQueryIndexedEXT vkCmdBeginQueryIndexedEXT;
extern PFN_vkCmdEndQueryIndexedEXT vkCmdEndQueryIndexedEXT;
extern PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT;
// Lazily load entry points for each extension as necessary. // Lazily load entry points for each extension as necessary.
void InitDebugUtilsEXTFunctions(VkInstance instance); void InitDebugUtilsEXTFunctions(VkInstance instance);
void InitDebugReportEXTFunctions(VkInstance instance); void InitDebugReportEXTFunctions(VkInstance instance);
void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance); void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance);
void InitTransformFeedbackEXTFunctions(VkDevice device);
#if defined(ANGLE_PLATFORM_FUCHSIA) #if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface // VK_FUCHSIA_imagepipe_surface
......
...@@ -1209,6 +1209,9 @@ TEST_P(TransformFeedbackTestES31, CaptureOutboundElement) ...@@ -1209,6 +1209,9 @@ TEST_P(TransformFeedbackTestES31, CaptureOutboundElement)
// Test transform feedback names can be specified using array element. // Test transform feedback names can be specified using array element.
TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings) TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings)
{ {
// Remove this when http://anglebug.com/4140 is fixed.
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kVS[] = constexpr char kVS[] =
"#version 310 es\n" "#version 310 es\n"
"in vec3 position;\n" "in vec3 position;\n"
...@@ -1271,6 +1274,9 @@ TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings) ...@@ -1271,6 +1274,9 @@ TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings)
// Test transform feedback varying for base-level members of struct. // Test transform feedback varying for base-level members of struct.
TEST_P(TransformFeedbackTestES31, StructMemberVaryings) TEST_P(TransformFeedbackTestES31, StructMemberVaryings)
{ {
// Remove this when http://anglebug.com/4140 is fixed.
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kVS[] = R"(#version 310 es constexpr char kVS[] = R"(#version 310 es
in vec3 position; in vec3 position;
struct S { struct S {
......
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