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
"Emulate transform feedback as the VK_EXT_transform_feedback is not present.", &members,
"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
Feature disableFifoPresentMode = {
"disable_fifo_present_mode", FeatureCategory::VulkanWorkarounds,
......
......@@ -207,6 +207,54 @@ size_t VariableExternalSize(GLenum 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)
{
switch (type)
......
......@@ -50,6 +50,7 @@ int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix);
int MatrixComponentCount(GLenum type, bool isRowMajorMatrix);
int VariableSortOrder(GLenum type);
GLenum VariableBoolVectorType(GLenum type);
std::string GetGLSLTypeString(GLenum type);
int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
......
......@@ -108,6 +108,11 @@ void TransformFeedback::onDestroy(const Context *context)
{
mState.mIndexedBuffers[i].set(context, nullptr, 0, 0);
}
if (mImplementation)
{
mImplementation->onDestroy(context);
}
}
TransformFeedback::~TransformFeedback()
......
......@@ -284,11 +284,16 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
{
std::set<std::string> uniqueFullNames;
mPackedVaryings.clear();
mInputVaryings.clear();
for (const auto &ref : mergedVaryings)
{
const sh::ShaderVariable *input = ref.second.frontShader;
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
// builtins. Note that we pack all statically used user-defined varyings even if they are
......
......@@ -182,6 +182,8 @@ class VaryingPacking final : angle::NonCopyable
return mInactiveVaryingNames;
}
const std::vector<sh::ShaderVariable> &getInputVaryings() const { return mInputVaryings; }
private:
bool packVarying(const PackedVarying &packedVarying);
bool isFree(unsigned int registerRow,
......@@ -194,6 +196,7 @@ class VaryingPacking final : angle::NonCopyable
std::vector<Register> mRegisterMap;
std::vector<PackedVaryingRegister> mRegisterList;
std::vector<sh::ShaderVariable> mInputVaryings;
std::vector<PackedVarying> mPackedVaryings;
std::vector<std::string> mInactiveVaryingNames;
......
......@@ -20,6 +20,7 @@ class TransformFeedbackImpl : angle::NonCopyable
public:
TransformFeedbackImpl(const gl::TransformFeedbackState &state) : mState(state) {}
virtual ~TransformFeedbackImpl() {}
virtual void onDestroy(const gl::Context *context) {}
virtual angle::Result begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) = 0;
virtual angle::Result end(const gl::Context *context) = 0;
......
......@@ -45,23 +45,25 @@ namespace rx
{
namespace
{
constexpr char kMarkerStart[] = "@@ ";
constexpr char kQualifierMarkerBegin[] = "@@ QUALIFIER-";
constexpr char kLayoutMarkerBegin[] = "@@ LAYOUT-";
constexpr char kXfbDeclMarkerBegin[] = "@@ XFB-DECL";
constexpr char kXfbOutMarkerBegin[] = "@@ XFB-OUT";
constexpr char kMarkerEnd[] = " @@";
constexpr char kParamsBegin = '(';
constexpr char kParamsEnd = ')';
constexpr char kUniformQualifier[] = "uniform";
constexpr char kSSBOQualifier[] = "buffer";
constexpr char kUnusedBlockSubstitution[] = "struct";
constexpr char kUnusedUniformSubstitution[] = "// ";
constexpr char kVersionDefine[] = "#version 450 core\n";
constexpr char kLineRasterDefine[] = R"(#version 450 core
constexpr char kMarkerStart[] = "@@ ";
constexpr char kQualifierMarkerBegin[] = "@@ QUALIFIER-";
constexpr char kLayoutMarkerBegin[] = "@@ LAYOUT-";
constexpr char kXfbDeclMarkerBegin[] = "@@ XFB-DECL";
constexpr char kXfbOutMarkerBegin[] = "@@ XFB-OUT";
constexpr char kMarkerEnd[] = " @@";
constexpr char kParamsBegin = '(';
constexpr char kParamsEnd = ')';
constexpr char kUniformQualifier[] = "uniform";
constexpr char kSSBOQualifier[] = "buffer";
constexpr char kUnusedBlockSubstitution[] = "struct";
constexpr char kUnusedUniformSubstitution[] = "// ";
constexpr char kVersionDefine[] = "#version 450 core\n";
constexpr char kLineRasterDefine[] = R"(#version 450 core
#define ANGLE_ENABLE_LINE_SEGMENT_RASTERIZATION
)";
constexpr uint32_t kANGLEPositionLocationOffset = 1;
constexpr uint32_t kXfbANGLEPositionLocationOffset = 2;
template <size_t N>
constexpr size_t ConstStrLen(const char (&)[N])
......@@ -106,6 +108,24 @@ void GetBuiltInResourcesFromCaps(const gl::Caps &caps, TBuiltInResource *outBuil
outBuiltInResources->maxVertexUniformVectors = caps.maxVertexUniformVectors;
}
// Information used for Xfb layout qualifier
struct XFBBufferInfo
{
GLuint index;
GLuint offset;
GLuint stride;
};
struct VaryingNameEquals
{
VaryingNameEquals(const std::string &name_) : name(name_) {}
bool operator()(const gl::TransformFeedbackVarying &var) const { return var.name == name; }
std::string name;
};
using XfbBufferMap = std::map<std::string, XFBBufferInfo>;
class IntermediateShaderSource final : angle::NonCopyable
{
public:
......@@ -464,9 +484,9 @@ std::string GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVa
return result.str();
}
void GenerateTransformFeedbackOutputs(const GlslangSourceOptions &options,
const gl::ProgramState &programState,
IntermediateShaderSource *vertexShader)
void GenerateTransformFeedbackEmulationOutputs(const GlslangSourceOptions &options,
const gl::ProgramState &programState,
IntermediateShaderSource *vertexShader)
{
const std::vector<gl::TransformFeedbackVarying> &varyings =
programState.getLinkedTransformFeedbackVaryings();
......@@ -514,6 +534,142 @@ void GenerateTransformFeedbackOutputs(const GlslangSourceOptions &options,
vertexShader->insertTransformFeedbackOutput(std::move(xfbOut));
}
// Calculates XFB layout quaifier arguments for each tranform feedback varyings, inserts
// layout quailifier for built-in varyings here and gathers calculated arguments for non built-in
// varyings for later use.
void GenerateTransformFeedbackExtensionOutputs(const gl::ProgramState &programState,
IntermediateShaderSource *vertexShader,
XfbBufferMap *xfbBufferMap,
const gl::ProgramLinkedResources &resources)
{
const std::vector<gl::TransformFeedbackVarying> &tfVaryings =
programState.getLinkedTransformFeedbackVaryings();
const std::vector<GLsizei> &varyingStrides = programState.getTransformFeedbackStrides();
const bool isInterleaved =
programState.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
std::string xfbDecl;
bool hasBuiltInVaryings = false;
bool replacePositionVarying = false;
uint32_t currentOffset = 0;
uint32_t currentStride = 0;
uint32_t bufferIndex = 0;
std::string varyingType;
std::string xfbIndices;
std::string xfbOffsets;
std::string xfbStrides;
std::string replacedPositionLayout;
for (uint32_t varyingIndex = 0; varyingIndex < tfVaryings.size(); ++varyingIndex)
{
if (isInterleaved)
{
bufferIndex = 0;
if (varyingIndex > 0)
{
const gl::TransformFeedbackVarying &prev = tfVaryings[varyingIndex - 1];
currentOffset += prev.size() * gl::VariableExternalSize(prev.type);
}
currentStride = varyingStrides[0];
}
else
{
bufferIndex = varyingIndex;
currentOffset = 0;
currentStride = varyingStrides[varyingIndex];
}
if (tfVaryings[varyingIndex].isBuiltIn())
{
xfbIndices = Str(bufferIndex);
xfbOffsets = Str(currentOffset);
xfbStrides = Str(currentStride);
varyingType = gl::GetGLSLTypeString(tfVaryings[varyingIndex].type);
if (tfVaryings[varyingIndex].name.compare("gl_Position") == 0)
{
replacePositionVarying = true;
std::string xfbReplacedPositionLocation =
Str(resources.varyingPacking.getMaxSemanticIndex() +
kXfbANGLEPositionLocationOffset);
replacedPositionLayout = "layout(location = " + xfbReplacedPositionLocation +
", xfb_buffer = " + xfbIndices +
", xfb_offset = " + xfbOffsets +
", xfb_stride = " + xfbStrides + ") out " + varyingType +
" xfbANGLEPosition;\n";
}
else
{
// Since built-in varyings are not in RegisterList, we can add layout qualifier
// here.
if (!hasBuiltInVaryings)
{
hasBuiltInVaryings = true;
xfbDecl += "out gl_PerVertex\n{\n";
for (uint32_t index = 0; index < tfVaryings.size(); ++index)
{
// need to add gl_Position to gl_Pervertex because we declared layout for
// replaced xfbANGLEPosition instead
if (tfVaryings[index].name.compare("gl_Position") == 0)
{
xfbDecl += "vec4 gl_Position;\n";
break;
}
}
}
xfbDecl += "layout(xfb_buffer = " + xfbIndices + ", xfb_offset = " + xfbOffsets +
", xfb_stride = " + xfbStrides + ") " + varyingType + " " +
tfVaryings[varyingIndex].name + ";\n";
}
}
else
{
// Layout qualifier for non built-in varying will be written later, so we just save
// Xfb layout qualifier information into the xfbBufferMap.
XFBBufferInfo bufferInfo;
bufferInfo.index = bufferIndex;
bufferInfo.offset = currentOffset;
bufferInfo.stride = currentStride;
xfbBufferMap->insert(make_pair(tfVaryings[varyingIndex].name, bufferInfo));
}
}
if (hasBuiltInVaryings)
{
// We should add non transform feedback built-in varyings to gl_PerVertex because once
// we declare gl_PerVertex, all built-in varyings used in shaders should be included
// in gl_PerVertex struct.
for (const sh::ShaderVariable &varying : resources.varyingPacking.getInputVaryings())
{
if (varying.isBuiltIn())
{
auto iter = std::find_if(tfVaryings.begin(), tfVaryings.end(),
VaryingNameEquals(varying.name));
if (iter == tfVaryings.end())
{
xfbDecl += gl::GetGLSLTypeString(varying.type) + " " + varying.name + ";\n";
}
}
}
xfbDecl += "\n};\n";
}
xfbDecl += replacedPositionLayout;
vertexShader->insertTransformFeedbackDeclaration(std::move(xfbDecl));
std::string xfbOut;
if (replacePositionVarying)
{
xfbOut += "xfbANGLEPosition = gl_Position;\n";
}
vertexShader->insertTransformFeedbackOutput(std::move(xfbOut));
}
void AssignAttributeLocations(const gl::ProgramState &programState,
IntermediateShaderSource *shaderSource)
{
......@@ -573,7 +729,8 @@ void AssignOutputLocations(const gl::ProgramState &programState,
void AssignVaryingLocations(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
IntermediateShaderSource *outStageSource,
IntermediateShaderSource *inStageSource)
IntermediateShaderSource *inStageSource,
XfbBufferMap *xfbBufferMap)
{
// Assign varying locations.
for (const gl::PackedVaryingRegister &varyingReg : resources.varyingPacking.getRegisterList())
......@@ -621,7 +778,20 @@ void AssignVaryingLocations(const gl::ProgramState &programState,
continue;
}
outStageSource->insertLayoutSpecifier(name, locationString);
XfbBufferMap::iterator iter;
iter = xfbBufferMap->find(name);
if (iter != xfbBufferMap->end())
{
XFBBufferInfo item = iter->second;
const std::string xfbSpecifier =
"xfb_buffer = " + Str(item.index) + ", xfb_offset = " + Str(item.offset) +
", xfb_stride = " + Str(item.stride) + ", " + locationString;
outStageSource->insertLayoutSpecifier(name, xfbSpecifier);
}
else
{
outStageSource->insertLayoutSpecifier(name, locationString);
}
inStageSource->insertLayoutSpecifier(name, locationString);
const char *outQualifier = "out";
......@@ -649,7 +819,8 @@ void AssignVaryingLocations(const gl::ProgramState &programState,
// varying register after the packed varyings.
constexpr char kVaryingName[] = "ANGLEPosition";
std::stringstream layoutStream;
layoutStream << "location = " << (resources.varyingPacking.getMaxSemanticIndex() + 1);
layoutStream << "location = "
<< (resources.varyingPacking.getMaxSemanticIndex() + kANGLEPositionLocationOffset);
const std::string layout = layoutStream.str();
outStageSource->insertLayoutSpecifier(kVaryingName, layout);
......@@ -1044,6 +1215,8 @@ std::string GlslangGetMappedSamplerName(const std::string &originalName)
void GlslangGetShaderSource(const GlslangSourceOptions &options,
bool useOldRewriteStructSamplers,
bool supportsTransformFeedbackExtension,
bool emulateTransformFeedback,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut)
......@@ -1062,28 +1235,55 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
IntermediateShaderSource *vertexSource = &intermediateSources[gl::ShaderType::Vertex];
IntermediateShaderSource *fragmentSource = &intermediateSources[gl::ShaderType::Fragment];
IntermediateShaderSource *geometrySource = &intermediateSources[gl::ShaderType::Geometry];
XfbBufferMap xfbBufferMap;
// Write transform feedback output code.
if (!vertexSource->empty())
{
if (programState.getLinkedTransformFeedbackVaryings().empty())
{
vertexSource->insertTransformFeedbackDeclaration("");
vertexSource->insertTransformFeedbackOutput("");
}
else
{
if (supportsTransformFeedbackExtension)
{
GenerateTransformFeedbackExtensionOutputs(programState, vertexSource, &xfbBufferMap,
resources);
}
else if (emulateTransformFeedback)
{
GenerateTransformFeedbackEmulationOutputs(options, programState, vertexSource);
}
}
}
if (!geometrySource->empty())
{
AssignOutputLocations(programState, fragmentSource);
AssignVaryingLocations(programState, resources, geometrySource, fragmentSource);
AssignVaryingLocations(programState, resources, geometrySource, fragmentSource,
&xfbBufferMap);
if (!vertexSource->empty())
{
AssignAttributeLocations(programState, vertexSource);
AssignVaryingLocations(programState, resources, vertexSource, geometrySource);
AssignVaryingLocations(programState, resources, vertexSource, geometrySource,
&xfbBufferMap);
}
}
else if (!vertexSource->empty())
{
AssignAttributeLocations(programState, vertexSource);
AssignOutputLocations(programState, fragmentSource);
AssignVaryingLocations(programState, resources, vertexSource, fragmentSource);
AssignVaryingLocations(programState, resources, vertexSource, fragmentSource,
&xfbBufferMap);
}
else if (!fragmentSource->empty())
{
AssignAttributeLocations(programState, fragmentSource);
AssignOutputLocations(programState, fragmentSource);
AssignVaryingLocations(programState, resources, vertexSource, fragmentSource);
AssignVaryingLocations(programState, resources, vertexSource, fragmentSource,
&xfbBufferMap);
}
AssignUniformBindings(options, &intermediateSources);
AssignTextureBindings(options, useOldRewriteStructSamplers, programState, &intermediateSources);
......@@ -1092,20 +1292,6 @@ void GlslangGetShaderSource(const GlslangSourceOptions &options,
CleanupUnusedEntities(useOldRewriteStructSamplers, programState, resources,
&intermediateSources);
// Write transform feedback output code.
if (!vertexSource->empty())
{
if (programState.getLinkedTransformFeedbackVaryings().empty())
{
vertexSource->insertTransformFeedbackDeclaration("");
vertexSource->insertTransformFeedbackOutput("");
}
else
{
GenerateTransformFeedbackOutputs(options, programState, vertexSource);
}
}
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
(*shaderSourcesOut)[shaderType] = intermediateSources[shaderType].getShaderSource();
......
......@@ -47,6 +47,8 @@ std::string GlslangGetMappedSamplerName(const std::string &originalName);
// resources (textures, buffers, xfb, etc)
void GlslangGetShaderSource(const GlslangSourceOptions &options,
bool useOldRewriteStructSamplers,
bool supportsTransformFeedbackExtension,
bool emulateTransformFeedback,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut);
......
......@@ -45,7 +45,7 @@ void GlslangGetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut)
{
rx::GlslangGetShaderSource(CreateSourceOptions(), false, programState, resources,
rx::GlslangGetShaderSource(CreateSourceOptions(), false, false, false, programState, resources,
shaderSourcesOut);
}
......
......@@ -102,12 +102,17 @@ angle::Result BufferVk::setData(const gl::Context *context,
// We could potentially use multiple backing buffers for different usages.
// 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_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_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 = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.flags = 0;
......
......@@ -207,6 +207,53 @@ void ExecuteCommands(PrimaryCommandBuffer *primCmdBuffer, priv::CommandBuffer *s
}
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)
{
return commandBuffer.dumpCommands(separator);
......@@ -381,7 +428,8 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function,
mGlobalMemoryBarrierSrcAccess(0),
mGlobalMemoryBarrierDstAccess(0),
mGlobalMemoryBarrierStages(0),
mRenderPassOwner(nullptr)
mRenderPassOwner(nullptr),
mValidTransformFeedbackBufferCount(0)
{}
CommandGraphNode::~CommandGraphNode()
......@@ -604,8 +652,26 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
beginInfo.pClearValues = mRenderPassClearValues.data();
primaryCommandBuffer->beginRenderPass(beginInfo, kRenderPassContents);
ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands);
primaryCommandBuffer->endRenderPass();
if (mValidTransformFeedbackBufferCount == 0)
{
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;
......
......@@ -205,6 +205,19 @@ class CommandGraphNode final : angle::NonCopyable
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.
void setRenderPassOwner(RenderPassOwner *owner)
{
......@@ -269,6 +282,11 @@ class CommandGraphNode final : angle::NonCopyable
// Render pass command buffer notifications.
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
......@@ -454,6 +472,11 @@ class CommandGraphResource : angle::NonCopyable
// Store a deferred memory barrier. Will be recorded into a primary command buffer at submit.
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:
explicit CommandGraphResource(CommandGraphResourceType resourceType);
......@@ -721,6 +744,16 @@ ANGLE_INLINE void CommandGraphResource::addGlobalMemoryBarrier(VkFlags srcAccess
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
{
// 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
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
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);
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE);
......@@ -558,8 +566,19 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
&ContextVk::handleDirtyGraphicsDriverUniforms;
mGraphicsDirtyBitHandlers[DIRTY_BIT_SHADER_RESOURCES] =
&ContextVk::handleDirtyGraphicsShaderResources;
mGraphicsDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
&ContextVk::handleDirtyGraphicsTransformFeedbackBuffers;
if (getFeatures().supportsTransformFeedbackExtension.enabled)
{
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] =
&ContextVk::handleDirtyGraphicsDescriptorSets;
......@@ -1170,7 +1189,7 @@ angle::Result ContextVk::handleDirtyComputeShaderResources(const gl::Context *co
return handleDirtyShaderResourcesImpl(context, commandBuffer, &mDispatcher);
}
angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffers(
angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffersEmulation(
const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
......@@ -1182,6 +1201,66 @@ angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffers(
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(
vk::CommandBuffer *commandBuffer,
VkPipelineBindPoint bindPoint,
......@@ -2655,12 +2734,27 @@ void ContextVk::onDrawFramebufferChange(FramebufferVk *framebufferVk)
void ContextVk::invalidateCurrentTransformFeedbackBuffers()
{
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,
......
......@@ -311,7 +311,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; }
void invalidateCurrentTransformFeedbackBuffers();
void onTransformFeedbackPauseResume();
void invalidateCurrentTransformFeedbackState();
void onTransformFeedbackStateChanged();
vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType);
......@@ -433,6 +434,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
DIRTY_BIT_DRIVER_UNIFORMS,
DIRTY_BIT_SHADER_RESOURCES, // excluding textures, which are handled separately.
DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
DIRTY_BIT_TRANSFORM_FEEDBACK_STATE,
DIRTY_BIT_DESCRIPTOR_SETS,
DIRTY_BIT_MAX,
};
......@@ -603,8 +605,14 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsShaderResources(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsTransformFeedbackBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyGraphicsTransformFeedbackBuffersEmulation(
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,
vk::CommandBuffer *commandBuffer);
......
......@@ -35,13 +35,15 @@ GlslangSourceOptions CreateSourceOptions()
} // namespace
// static
void GlslangWrapperVk::GetShaderSource(bool useOldRewriteStructSamplers,
void GlslangWrapperVk::GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut)
{
GlslangGetShaderSource(CreateSourceOptions(), useOldRewriteStructSamplers, programState,
resources, shaderSourcesOut);
GlslangGetShaderSource(CreateSourceOptions(), features.forceOldRewriteStructSamplers.enabled,
features.supportsTransformFeedbackExtension.enabled,
features.emulateTransformFeedback.enabled, programState, resources,
shaderSourcesOut);
}
// static
......
......@@ -12,6 +12,11 @@
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace angle
{
struct FeaturesVk;
} // namespace angle
namespace rx
{
// This class currently holds no state. If we want to hold state we would need to solve the
......@@ -19,7 +24,7 @@ namespace rx
class GlslangWrapperVk
{
public:
static void GetShaderSource(bool useOldRewriteStructSamplers,
static void GetShaderSource(const angle::FeaturesVk &features,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::ShaderMap<std::string> *shaderSourcesOut);
......
......@@ -566,7 +566,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
// assignment done in that function.
linkResources(resources);
GlslangWrapperVk::GetShaderSource(contextVk->useOldRewriteStructSamplers(), mState, resources,
GlslangWrapperVk::GetShaderSource(contextVk->getRenderer()->getFeatures(), mState, resources,
&mShaderSources);
reset(contextVk);
......@@ -606,7 +606,8 @@ angle::Result ProgramVk::linkImpl(const gl::Context *glContext, gl::InfoLog &inf
if (mState.hasLinkedShaderStage(gl::ShaderType::Vertex) && transformFeedback &&
!mState.getLinkedTransformFeedbackVaryings().empty())
{
vk::GetImpl(transformFeedback)->updateDescriptorSetLayout(mState, &uniformsAndXfbSetDesc);
TransformFeedbackVk *transformFeedbackVk = vk::GetImpl(transformFeedback);
transformFeedbackVk->updateDescriptorSetLayout(contextVk, mState, &uniformsAndXfbSetDesc);
}
ANGLE_TRY(renderer->getDescriptorSetLayout(
......
......@@ -1062,7 +1062,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
std::sort(enabledDeviceExtensions.begin(), enabledDeviceExtensions.end(), StrLess);
ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionNames, enabledDeviceExtensions));
// Select additional features to be enabled
// Select additional features to be enabled.
VkPhysicalDeviceFeatures2KHR enabledFeatures = {};
enabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend;
......@@ -1073,6 +1073,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.fragmentStoresAndAtomics =
mPhysicalDeviceFeatures.fragmentStoresAndAtomics;
enabledFeatures.features.geometryShader = mPhysicalDeviceFeatures.geometryShader;
if (!vk::CommandBuffer::ExecutesInline())
{
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
......@@ -1118,6 +1119,18 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
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.ppEnabledExtensionNames =
enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
......@@ -1128,6 +1141,11 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
vkGetDeviceQueue(mDevice, mCurrentQueueFamilyIndex, 0, &mQueue);
if (supportsTransformFeedbackExt)
{
InitTransformFeedbackEXTFunctions(mDevice);
}
// Initialize the vulkan pipeline cache.
bool success = false;
ANGLE_TRY(initPipelineCache(displayVk, &mPipelineCache, &success));
......@@ -1278,12 +1296,13 @@ gl::Version RendererVk::getMaxSupportedESVersion() const
maxVersion = std::max(maxVersion, gl::Version(2, 0));
}
// If vertexPipelineStoresAndAtomics is not supported, we can't currently support transform
// feedback. TODO(syoussefi): this should be conditioned to the extension not being present as
// well, when that code path is implemented. http://anglebug.com/3206
if (!mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
// If the Vulkan transform feedback extension is not present, we use an emulation path that
// requires the vertexPipelineStoresAndAtomics feature. Without the extension or this feature,
// we can't currently support transform feedback.
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.
......@@ -1395,10 +1414,13 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
(&mFeatures), supportsShaderStencilExport,
ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames));
// TODO(syoussefi): when the code path using the extension is implemented, this should be
// conditioned to the extension not being present as well. http://anglebug.com/3206
ANGLE_FEATURE_CONDITION(
(&mFeatures), supportsTransformFeedbackExtension,
ExtensionFound(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, deviceExtensionNames));
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);
......
......@@ -9,6 +9,7 @@
#include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h"
#include "common/debug.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
namespace rx
{
......@@ -75,6 +76,20 @@ void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer)
params->indexType);
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:
{
const BindVertexBuffersParams *params =
......@@ -431,6 +446,9 @@ std::string SecondaryCommandBuffer::dumpCommands(const char *separator) const
case CommandID::BindVertexBuffers:
result += "BindVertexBuffers";
break;
case CommandID::BindTransformFeedbackBuffers:
result += "BindTransformFeedbackBuffers";
break;
case CommandID::BlitImage:
result += "BlitImage";
break;
......
......@@ -34,6 +34,7 @@ enum class CommandID : uint16_t
BindDescriptorSets,
BindGraphicsPipeline,
BindIndexBuffer,
BindTransformFeedbackBuffers,
BindVertexBuffers,
BlitImage,
BufferBarrier,
......@@ -102,6 +103,13 @@ struct 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
{
// ANGLE always has firstBinding of 0 so not storing that currently
......@@ -443,6 +451,11 @@ class SecondaryCommandBuffer final : angle::NonCopyable
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,
uint32_t bindingCount,
const VkBuffer *buffers,
......@@ -777,6 +790,26 @@ ANGLE_INLINE void SecondaryCommandBuffer::bindIndexBuffer(const Buffer &buffer,
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,
uint32_t bindingCount,
const VkBuffer *buffers,
......
......@@ -23,21 +23,36 @@ namespace rx
{
TransformFeedbackVk::TransformFeedbackVk(const gl::TransformFeedbackState &state)
: TransformFeedbackImpl(state)
{}
: TransformFeedbackImpl(state), mRebindTransformFeedbackBuffer(false)
{
mCounterBufferHandles.fill(0);
}
TransformFeedbackVk::~TransformFeedbackVk() {}
void TransformFeedbackVk::onDestroy(const gl::Context *context)
{
RendererVk *rendererVk = vk::GetImpl(context)->getRenderer();
for (vk::BufferHelper &bufferHelper : mCounterBuffer)
{
bufferHelper.release(rendererVk);
}
}
angle::Result TransformFeedbackVk::begin(const gl::Context *context,
gl::PrimitiveMode primitiveMode)
{
ContextVk *contextVk = vk::GetImpl(context);
// Make sure the transform feedback buffers are bound to the program descriptor sets.
contextVk->invalidateCurrentTransformFeedbackBuffers();
contextVk->onTransformFeedbackStateChanged();
vk::GetImpl(context)->onTransformFeedbackPauseResume();
onBeginOrEnd(context);
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
mRebindTransformFeedbackBuffer = true;
}
onTransformFeedbackStateChanged(context);
return angle::Result::Continue;
}
......@@ -48,26 +63,48 @@ angle::Result TransformFeedbackVk::end(const gl::Context *context)
const gl::State &glState = context->getState();
gl::Query *transformFeedbackQuery =
glState.getActiveQuery(gl::QueryType::TransformFeedbackPrimitivesWritten);
if (transformFeedbackQuery)
{
vk::GetImpl(transformFeedbackQuery)->onTransformFeedbackEnd(context);
}
vk::GetImpl(context)->onTransformFeedbackPauseResume();
onBeginOrEnd(context);
vk::GetImpl(context)->onTransformFeedbackStateChanged();
onTransformFeedbackStateChanged(context);
return angle::Result::Continue;
}
angle::Result TransformFeedbackVk::pause(const gl::Context *context)
{
vk::GetImpl(context)->onTransformFeedbackPauseResume();
ContextVk *contextVk = vk::GetImpl(context);
contextVk->onTransformFeedbackStateChanged();
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
// We need to create new commandGraphNode to perform transform feedback pause/resume
// becasue vkCmdBegin/EndTransformFeedback can be placed once per commandGraphNode.
onTransformFeedbackStateChanged(context);
}
return angle::Result::Continue;
}
angle::Result TransformFeedbackVk::resume(const gl::Context *context)
{
vk::GetImpl(context)->onTransformFeedbackPauseResume();
ContextVk *contextVk = vk::GetImpl(context);
contextVk->onTransformFeedbackStateChanged();
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
// We need to create new commandGraphNode to perform transform feedback pause/resume
// becasue vkCmdBegin/EndTransformFeedback can be placed once per commandGraphNode.
onTransformFeedbackStateChanged(context);
}
return angle::Result::Continue;
}
......@@ -76,27 +113,63 @@ angle::Result TransformFeedbackVk::bindIndexedBuffer(
size_t index,
const gl::OffsetBindingPointer<gl::Buffer> &binding)
{
RendererVk *rendererVk = vk::GetImpl(context)->getRenderer();
const VkDeviceSize offsetAlignment =
rendererVk->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
ContextVk *contextVk = vk::GetImpl(context);
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
// Save xfb buffer state
mTransformFeedbackBufferRange.offsets[index] = binding.getOffset();
mTransformFeedbackBufferRange.sizes[index] =
(binding.getSize()) ? binding.getSize() : VK_WHOLE_SIZE;
mRebindTransformFeedbackBuffer = true;
if (mCounterBufferHandles[index] == 0)
{
VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.size = 16;
createInfo.usage = VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT;
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ANGLE_TRY(mCounterBuffer[index].init(contextVk, createInfo,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
mCounterBufferHandles[index] = mCounterBuffer[index].getBuffer().getHandle();
}
// Set dirty bit for update xfb buffer
contextVk->invalidateCurrentTransformFeedbackBuffers();
}
else if (contextVk->getFeatures().emulateTransformFeedback.enabled)
{
RendererVk *rendererVk = vk::GetImpl(context)->getRenderer();
const VkDeviceSize offsetAlignment =
rendererVk->getPhysicalDeviceProperties().limits.minStorageBufferOffsetAlignment;
// Make sure there's no possible under/overflow with binding size.
static_assert(sizeof(VkDeviceSize) >= sizeof(binding.getSize()), "VkDeviceSize too small");
// Make sure there's no possible under/overflow with binding size.
static_assert(sizeof(VkDeviceSize) >= sizeof(binding.getSize()), "VkDeviceSize too small");
mBoundBufferRanges[index].offset = binding.getOffset();
mBoundBufferRanges[index].size = gl::GetBoundBufferAvailableSize(binding);
mTransformFeedbackBufferRange.offsets[index] = binding.getOffset();
mTransformFeedbackBufferRange.sizes[index] = gl::GetBoundBufferAvailableSize(binding);
// Set the offset as close as possible to the requested offset while remaining aligned.
mBoundBufferRanges[index].alignedOffset =
(mBoundBufferRanges[index].offset / offsetAlignment) * offsetAlignment;
// Set the offset as close as possible to the requested offset while remaining aligned.
mTransformFeedbackBufferRange.alignedOffsets[index] =
(mTransformFeedbackBufferRange.offsets[index] / offsetAlignment) * offsetAlignment;
// Make sure the transform feedback buffers are bound to the program descriptor sets.
contextVk->invalidateCurrentTransformFeedbackBuffers();
}
return angle::Result::Continue;
}
void TransformFeedbackVk::updateDescriptorSetLayout(
ContextVk *contextVk,
const gl::ProgramState &programState,
vk::DescriptorSetLayoutDesc *descSetLayoutOut) const
{
if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
return;
size_t xfbBufferCount = programState.getTransformFeedbackBufferCount();
for (uint32_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
......@@ -118,6 +191,12 @@ void TransformFeedbackVk::addFramebufferDependency(ContextVk *contextVk,
ASSERT(programState.getTransformFeedbackBufferMode() != GL_INTERLEAVED_ATTRIBS ||
xfbBufferCount == 1);
VkAccessFlags writeAccessType = VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT;
if (!contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
writeAccessType = VK_ACCESS_SHADER_WRITE_BIT;
}
// Set framebuffer dependent to the transform feedback buffers. This is especially done
// separately from |updateDescriptorSet|, to avoid introducing unnecessary buffer barriers
// every time the descriptor set is updated (which, as the set is shared with default uniforms,
......@@ -129,7 +208,7 @@ void TransformFeedbackVk::addFramebufferDependency(ContextVk *contextVk,
ASSERT(buffer != nullptr);
vk::BufferHelper &bufferHelper = vk::GetImpl(buffer)->getBuffer();
bufferHelper.onWrite(contextVk, framebuffer, VK_ACCESS_SHADER_WRITE_BIT);
bufferHelper.onWrite(contextVk, framebuffer, writeAccessType);
}
}
......@@ -138,6 +217,9 @@ void TransformFeedbackVk::initDescriptorSet(ContextVk *contextVk,
vk::BufferHelper *emptyBuffer,
VkDescriptorSet descSet) const
{
if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
return;
std::array<VkDescriptorBufferInfo, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>
descriptorBufferInfo;
......@@ -156,6 +238,9 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState,
VkDescriptorSet descSet) const
{
if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
return;
const std::vector<gl::OffsetBindingPointer<gl::Buffer>> &xfbBuffers =
mState.getIndexedBuffers();
size_t xfbBufferCount = programState.getTransformFeedbackBufferCount();
......@@ -170,8 +255,7 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
// Write default uniforms for each shader type.
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[bufferIndex];
const BoundBufferRange &bufferRange = mBoundBufferRanges[bufferIndex];
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[bufferIndex];
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = xfbBuffers[bufferIndex];
gl::Buffer *buffer = bufferBinding.get();
......@@ -180,8 +264,10 @@ void TransformFeedbackVk::updateDescriptorSet(ContextVk *contextVk,
vk::BufferHelper &bufferHelper = vk::GetImpl(buffer)->getBuffer();
bufferInfo.buffer = bufferHelper.getBuffer().getHandle();
bufferInfo.offset = bufferRange.alignedOffset;
bufferInfo.range = bufferRange.size + (bufferRange.offset - bufferRange.alignedOffset);
bufferInfo.offset = mTransformFeedbackBufferRange.alignedOffsets[bufferIndex];
bufferInfo.range = mTransformFeedbackBufferRange.sizes[bufferIndex] +
(mTransformFeedbackBufferRange.offsets[bufferIndex] -
mTransformFeedbackBufferRange.alignedOffsets[bufferIndex]);
}
writeDescriptorSet(contextVk, xfbBufferCount, descriptorBufferInfo.data(), descSet);
......@@ -193,6 +279,9 @@ void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
int32_t *offsetsOut,
size_t offsetsSize) const
{
if (!contextVk->getFeatures().emulateTransformFeedback.enabled)
return;
GLsizeiptr verticesDrawn = mState.getVerticesDrawn();
const std::vector<GLsizei> &bufferStrides =
mState.getBoundProgram()->getTransformFeedbackStrides();
......@@ -200,16 +289,15 @@ void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
ASSERT(xfbBufferCount > 0);
// The caller should make sure the offsets array has enough space. The maximum possible number
// of outputs is gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS.
// The caller should make sure the offsets array has enough space. The maximum possible
// number of outputs is gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS.
ASSERT(offsetsSize >= xfbBufferCount);
for (size_t bufferIndex = 0; bufferIndex < xfbBufferCount; ++bufferIndex)
{
const BoundBufferRange &bufferRange = mBoundBufferRanges[bufferIndex];
int64_t offsetFromDescriptor =
static_cast<int64_t>(bufferRange.offset - bufferRange.alignedOffset);
static_cast<int64_t>(mTransformFeedbackBufferRange.offsets[bufferIndex] -
mTransformFeedbackBufferRange.alignedOffsets[bufferIndex]);
int64_t drawCallVertexOffset = static_cast<int64_t>(verticesDrawn) - drawCallFirstVertex;
int64_t writeOffset =
......@@ -223,7 +311,7 @@ void TransformFeedbackVk::getBufferOffsets(ContextVk *contextVk,
}
}
void TransformFeedbackVk::onBeginOrEnd(const gl::Context *context)
void TransformFeedbackVk::onTransformFeedbackStateChanged(const gl::Context *context)
{
// 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
......
......@@ -25,11 +25,24 @@ namespace vk
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
{
public:
TransformFeedbackVk(const gl::TransformFeedbackState &state);
~TransformFeedbackVk() override;
void onDestroy(const gl::Context *context) override;
angle::Result begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) override;
angle::Result end(const gl::Context *context) override;
......@@ -40,7 +53,8 @@ class TransformFeedbackVk : public TransformFeedbackImpl
size_t index,
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;
void addFramebufferDependency(ContextVk *contextVk,
const gl::ProgramState &programState,
......@@ -58,25 +72,36 @@ class TransformFeedbackVk : public TransformFeedbackImpl
int32_t *offsetsOut,
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:
void onBeginOrEnd(const gl::Context *context);
void onTransformFeedbackStateChanged(const gl::Context *context);
void writeDescriptorSet(ContextVk *contextVk,
size_t xfbBufferCount,
VkDescriptorBufferInfo *pBufferInfo,
VkDescriptorSet descSet) const;
// Cached buffer properties for faster descriptor set update and offset calculation.
struct BoundBufferRange
{
// Offset as provided by OffsetBindingPointer.
VkDeviceSize offset = 0;
// Size as provided by OffsetBindingPointer.
VkDeviceSize size = 0;
// Aligned offset usable for VkDescriptorBufferInfo. This value could be smaller than
// offset.
VkDeviceSize alignedOffset = 0;
};
gl::TransformFeedbackBuffersArray<BoundBufferRange> mBoundBufferRanges;
// This member variable is set when glBindTransformFeedbackBuffers/glBeginTransformFeedback
// 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
// of the buffer.
bool mRebindTransformFeedbackBuffer;
TransformFeedbackBufferRange mTransformFeedbackBufferRange;
// Counter buffer used for pause and resume.
gl::TransformFeedbackBuffersArray<vk::BufferHelper> mCounterBuffer;
gl::TransformFeedbackBuffersArray<VkBuffer> mCounterBufferHandles;
};
} // 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(
*pNextPtr = &provokingVertexState;
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.
multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
......
......@@ -563,43 +563,68 @@ PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR = nullpt
// VK_KHR_external_semaphore_fd
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)
// VK_FUCHSIA_imagepipe_surface
PFN_vkCreateImagePipeSurfaceFUCHSIA vkCreateImagePipeSurfaceFUCHSIA = nullptr;
#endif
#define GET_FUNC(vkName) \
#define GET_INSTANCE_FUNC(vkName) \
do \
{ \
vkName = reinterpret_cast<PFN_##vkName>(vkGetInstanceProcAddr(instance, #vkName)); \
ASSERT(vkName); \
} while (0)
#define GET_DEVICE_FUNC(vkName) \
do \
{ \
vkName = reinterpret_cast<PFN_##vkName>(vkGetDeviceProcAddr(device, #vkName)); \
ASSERT(vkName); \
} while (0)
void InitDebugUtilsEXTFunctions(VkInstance instance)
{
GET_FUNC(vkCreateDebugUtilsMessengerEXT);
GET_FUNC(vkDestroyDebugUtilsMessengerEXT);
GET_FUNC(vkCmdBeginDebugUtilsLabelEXT);
GET_FUNC(vkCmdEndDebugUtilsLabelEXT);
GET_FUNC(vkCmdInsertDebugUtilsLabelEXT);
GET_INSTANCE_FUNC(vkCreateDebugUtilsMessengerEXT);
GET_INSTANCE_FUNC(vkDestroyDebugUtilsMessengerEXT);
GET_INSTANCE_FUNC(vkCmdBeginDebugUtilsLabelEXT);
GET_INSTANCE_FUNC(vkCmdEndDebugUtilsLabelEXT);
GET_INSTANCE_FUNC(vkCmdInsertDebugUtilsLabelEXT);
}
void InitDebugReportEXTFunctions(VkInstance instance)
{
GET_FUNC(vkCreateDebugReportCallbackEXT);
GET_FUNC(vkDestroyDebugReportCallbackEXT);
GET_INSTANCE_FUNC(vkCreateDebugReportCallbackEXT);
GET_INSTANCE_FUNC(vkDestroyDebugReportCallbackEXT);
}
void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance)
{
GET_FUNC(vkGetPhysicalDeviceProperties2KHR);
GET_FUNC(vkGetPhysicalDeviceFeatures2KHR);
GET_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR);
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)
void InitImagePipeSurfaceFUCHSIAFunctions(VkInstance instance)
{
GET_FUNC(vkCreateImagePipeSurfaceFUCHSIA);
GET_INSTANCE_FUNC(vkCreateImagePipeSurfaceFUCHSIA);
}
#endif
......@@ -609,8 +634,8 @@ PFN_vkGetAndroidHardwareBufferPropertiesANDROID vkGetAndroidHardwareBufferProper
PFN_vkGetMemoryAndroidHardwareBufferANDROID vkGetMemoryAndroidHardwareBufferANDROID = nullptr;
void InitExternalMemoryHardwareBufferANDROIDFunctions(VkInstance instance)
{
GET_FUNC(vkGetAndroidHardwareBufferPropertiesANDROID);
GET_FUNC(vkGetMemoryAndroidHardwareBufferANDROID);
GET_INSTANCE_FUNC(vkGetAndroidHardwareBufferPropertiesANDROID);
GET_INSTANCE_FUNC(vkGetMemoryAndroidHardwareBufferANDROID);
}
#endif
......@@ -625,10 +650,11 @@ void InitGGPStreamDescriptorSurfaceFunctions(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
{
......
......@@ -625,10 +625,18 @@ extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
// VK_KHR_external_semaphore_fd
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.
void InitDebugUtilsEXTFunctions(VkInstance instance);
void InitDebugReportEXTFunctions(VkInstance instance);
void InitGetPhysicalDeviceProperties2KHRFunctions(VkInstance instance);
void InitTransformFeedbackEXTFunctions(VkDevice device);
#if defined(ANGLE_PLATFORM_FUCHSIA)
// VK_FUCHSIA_imagepipe_surface
......
......@@ -1209,6 +1209,9 @@ TEST_P(TransformFeedbackTestES31, CaptureOutboundElement)
// Test transform feedback names can be specified using array element.
TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings)
{
// Remove this when http://anglebug.com/4140 is fixed.
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kVS[] =
"#version 310 es\n"
"in vec3 position;\n"
......@@ -1271,6 +1274,9 @@ TEST_P(TransformFeedbackTestES31, DifferentArrayElementVaryings)
// Test transform feedback varying for base-level members of struct.
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
in vec3 position;
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