Commit 0bfa5504 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Emulate Transform Feedback with vertex shader output

In ES 3.0 and 3.1, only non-indexed GL_POINTS, GL_LINES and GL_TRIANGLES is supported for transform feedback. Without tessellation and geometry shaders, we can calculate the exact location where each vertex transform output should be written on the CPU, and have each vertex shader invocation write its data separately to the appropriate location in the buffer. This depends on the vertexPipelineStoresAndAtomics Vulkan feature. Bug: angleproject:3205 Change-Id: I68ccbb80aece597cf20c557a0aee842360fea593 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1645678 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 235e56fb
...@@ -118,6 +118,13 @@ struct FeaturesVk : FeatureSetBase ...@@ -118,6 +118,13 @@ struct FeaturesVk : FeatureSetBase
"supports_shader_stencil_export", FeatureCategory::VulkanFeatures, "supports_shader_stencil_export", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_EXT_shader_stencil_export extension", &members}; "VkDevice supports the VK_EXT_shader_stencil_export extension", &members};
// Where VK_EXT_transform_feedback is not support, an emulation path is used.
// http://anglebug.com/3205
Feature emulateTransformFeedback = {
"emulate_transform_feedback", FeatureCategory::VulkanFeatures,
"Emulate transform feedback as the VK_EXT_transform_feedback is not present.", &members,
"http://anglebug.com/3205"};
// 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,
......
...@@ -466,7 +466,7 @@ ...@@ -466,7 +466,7 @@
"proc table:src/libGLESv2/proc_table_autogen.cpp": "proc table:src/libGLESv2/proc_table_autogen.cpp":
"e82a9970d6059a7c8b562726e3f219a4", "e82a9970d6059a7c8b562726e3f219a4",
"uniform type:src/common/gen_uniform_type_table.py": "uniform type:src/common/gen_uniform_type_table.py":
"9dd389f2b5793ba635169d61cef2dde9", "a741cc301b1617ab0e4d29b35f1d3b96",
"uniform type:src/common/uniform_type_info_autogen.cpp": "uniform type:src/common/uniform_type_info_autogen.cpp":
"b31d181bc49ad1c3540401a5c874e692" "d1cea53e456de010445790b8de94a50e"
} }
\ No newline at end of file
...@@ -94,7 +94,7 @@ const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType) ...@@ -94,7 +94,7 @@ const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType)
}} // namespace gl }} // namespace gl
""" """
type_info_data_template = """{{{type}, {component_type}, {texture_type}, {transposed_type}, {bool_type}, {sampler_format}, {rows}, {columns}, {components}, {component_size}, {internal_size}, {external_size}, {is_sampler}, {is_matrix}, {is_image} }}""" type_info_data_template = """{{{type}, {component_type}, {texture_type}, {transposed_type}, {bool_type}, {sampler_format}, {rows}, {columns}, {components}, {component_size}, {internal_size}, {external_size}, {is_sampler}, {is_matrix}, {is_image}, {glsl_asfloat} }}"""
type_index_case_template = """case {enum_value}: return {index_value};""" type_index_case_template = """case {enum_value}: return {index_value};"""
...@@ -183,15 +183,15 @@ def get_components(uniform_type): ...@@ -183,15 +183,15 @@ def get_components(uniform_type):
def get_component_size(uniform_type): def get_component_size(uniform_type):
component_type = get_component_type(uniform_type) component_type = get_component_type(uniform_type)
if (component_type) == "GL_BOOL": if component_type == "GL_BOOL":
return "sizeof(GLint)" return "sizeof(GLint)"
elif (component_type) == "GL_FLOAT": elif component_type == "GL_FLOAT":
return "sizeof(GLfloat)" return "sizeof(GLfloat)"
elif (component_type) == "GL_INT": elif component_type == "GL_INT":
return "sizeof(GLint)" return "sizeof(GLint)"
elif (component_type) == "GL_UNSIGNED_INT": elif component_type == "GL_UNSIGNED_INT":
return "sizeof(GLuint)" return "sizeof(GLuint)"
elif (component_type) == "GL_NONE": elif component_type == "GL_NONE":
return "0" return "0"
else: else:
raise "Invalid component type: " + component_type raise "Invalid component type: " + component_type
...@@ -217,6 +217,22 @@ def get_is_image(uniform_type): ...@@ -217,6 +217,22 @@ def get_is_image(uniform_type):
return cpp_bool("_IMAGE_" in uniform_type) return cpp_bool("_IMAGE_" in uniform_type)
def get_glsl_asfloat(uniform_type):
component_type = get_component_type(uniform_type)
if component_type == "GL_BOOL":
return '""'
elif component_type == "GL_FLOAT":
return '""'
elif component_type == "GL_INT":
return '"intBitsToFloat"'
elif component_type == "GL_UNSIGNED_INT":
return '"uintBitsToFloat"'
elif component_type == "GL_NONE":
return '""'
else:
raise "Invalid component type: " + component_type
def gen_type_info(uniform_type): def gen_type_info(uniform_type):
return type_info_data_template.format( return type_info_data_template.format(
type=uniform_type, type=uniform_type,
...@@ -233,7 +249,8 @@ def gen_type_info(uniform_type): ...@@ -233,7 +249,8 @@ def gen_type_info(uniform_type):
external_size=get_external_size(uniform_type), external_size=get_external_size(uniform_type),
is_sampler=get_is_sampler(uniform_type), is_sampler=get_is_sampler(uniform_type),
is_matrix=get_is_matrix(uniform_type), is_matrix=get_is_matrix(uniform_type),
is_image=get_is_image(uniform_type)) is_image=get_is_image(uniform_type),
glsl_asfloat=get_glsl_asfloat(uniform_type))
def gen_type_index_case(index, uniform_type): def gen_type_index_case(index, uniform_type):
......
...@@ -139,7 +139,8 @@ struct UniformTypeInfo final : angle::NonCopyable ...@@ -139,7 +139,8 @@ struct UniformTypeInfo final : angle::NonCopyable
size_t externalSize, size_t externalSize,
bool isSampler, bool isSampler,
bool isMatrixType, bool isMatrixType,
bool isImageType); bool isImageType,
const char *glslAsFloat);
GLenum type; GLenum type;
GLenum componentType; GLenum componentType;
...@@ -156,6 +157,7 @@ struct UniformTypeInfo final : angle::NonCopyable ...@@ -156,6 +157,7 @@ struct UniformTypeInfo final : angle::NonCopyable
bool isSampler; bool isSampler;
bool isMatrixType; bool isMatrixType;
bool isImageType; bool isImageType;
const char *glslAsFloat;
}; };
inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type, inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
...@@ -172,7 +174,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type, ...@@ -172,7 +174,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
size_t externalSize, size_t externalSize,
bool isSampler, bool isSampler,
bool isMatrixType, bool isMatrixType,
bool isImageType) bool isImageType,
const char *glslAsFloat)
: type(type), : type(type),
componentType(componentType), componentType(componentType),
textureType(textureType), textureType(textureType),
...@@ -187,7 +190,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type, ...@@ -187,7 +190,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
externalSize(externalSize), externalSize(externalSize),
isSampler(isSampler), isSampler(isSampler),
isMatrixType(isMatrixType), isMatrixType(isMatrixType),
isImageType(isImageType) isImageType(isImageType),
glslAsFloat(glslAsFloat)
{} {}
const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType); const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType);
......
...@@ -157,12 +157,14 @@ constexpr const char kViewport[] = "viewport"; ...@@ -157,12 +157,14 @@ constexpr const char kViewport[] = "viewport";
constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight"; constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight";
constexpr const char kViewportYScale[] = "viewportYScale"; constexpr const char kViewportYScale[] = "viewportYScale";
constexpr const char kNegViewportYScale[] = "negViewportYScale"; constexpr const char kNegViewportYScale[] = "negViewportYScale";
constexpr const char kXfbActiveUnpaused[] = "xfbActiveUnpaused";
constexpr const char kXfbBufferOffsets[] = "xfbBufferOffsets";
constexpr const char kDepthRange[] = "depthRange"; constexpr const char kDepthRange[] = "depthRange";
constexpr size_t kNumDriverUniforms = 6; constexpr size_t kNumDriverUniforms = 7;
constexpr std::array<const char *, kNumDriverUniforms> kDriverUniformNames = { constexpr std::array<const char *, kNumDriverUniforms> kDriverUniformNames = {
{kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, "padding", {kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, kXfbActiveUnpaused,
kDepthRange}}; kXfbBufferOffsets, kDepthRange}};
template <TBasicType BasicType = EbtFloat, unsigned char PrimarySize = 1> template <TBasicType BasicType = EbtFloat, unsigned char PrimarySize = 1>
TIntermConstantUnion *CreateBasicConstant(float value) TIntermConstantUnion *CreateBasicConstant(float value)
...@@ -359,7 +361,8 @@ const TVariable *AddDriverUniformsToShader(TIntermBlock *root, TSymbolTable *sym ...@@ -359,7 +361,8 @@ const TVariable *AddDriverUniformsToShader(TIntermBlock *root, TSymbolTable *sym
new TType(EbtFloat), new TType(EbtFloat),
new TType(EbtFloat), new TType(EbtFloat),
new TType(EbtFloat), new TType(EbtFloat),
new TType(EbtFloat), new TType(EbtUInt),
new TType(EbtInt, 4),
emulatedDepthRangeType, emulatedDepthRangeType,
}}; }};
......
...@@ -44,6 +44,7 @@ class BufferState final : angle::NonCopyable ...@@ -44,6 +44,7 @@ class BufferState final : angle::NonCopyable
GLint64 getMapOffset() const { return mMapOffset; } GLint64 getMapOffset() const { return mMapOffset; }
GLint64 getMapLength() const { return mMapLength; } GLint64 getMapLength() const { return mMapLength; }
GLint64 getSize() const { return mSize; } GLint64 getSize() const { return mSize; }
bool isBoundForTransformFeedback() const { return mTransformFeedbackIndexedBindingCount != 0; }
private: private:
friend class Buffer; friend class Buffer;
......
...@@ -41,7 +41,11 @@ enum ...@@ -41,7 +41,11 @@ enum
// GL_EXT_geometry_shader increases the minimum value of GL_MAX_UNIFORM_BUFFER_BINDINGS to 48. // GL_EXT_geometry_shader increases the minimum value of GL_MAX_UNIFORM_BUFFER_BINDINGS to 48.
IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS = 48, IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS = 48,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4, // Transform feedback limits set to the minimum required by the spec.
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 64,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 4,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 4,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS = 4,
// Maximum number of views which are supported by the implementation of ANGLE_multiview. // Maximum number of views which are supported by the implementation of ANGLE_multiview.
IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS = 4, IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS = 4,
......
...@@ -3301,6 +3301,13 @@ void Context::initCaps() ...@@ -3301,6 +3301,13 @@ void Context::initCaps()
LimitCap(&mState.mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); LimitCap(&mState.mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
LimitCap(&mState.mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); LimitCap(&mState.mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
LimitCap(&mState.mCaps.maxTransformFeedbackInterleavedComponents,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
LimitCap(&mState.mCaps.maxTransformFeedbackSeparateAttributes,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
LimitCap(&mState.mCaps.maxTransformFeedbackSeparateComponents,
IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
// Limit textures as well, so we can use fast bitsets with texture bindings. // Limit textures as well, so we can use fast bitsets with texture bindings.
LimitCap(&mState.mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES); LimitCap(&mState.mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
LimitCap(&mState.mCaps.maxShaderTextureImageUnits[ShaderType::Vertex], LimitCap(&mState.mCaps.maxShaderTextureImageUnits[ShaderType::Vertex],
......
...@@ -1423,15 +1423,16 @@ angle::Result Program::link(const Context *context) ...@@ -1423,15 +1423,16 @@ angle::Result Program::link(const Context *context)
} }
gatherTransformFeedbackVaryings(mergedVaryings); gatherTransformFeedbackVaryings(mergedVaryings);
mState.updateTransformFeedbackStrides();
} }
mLinkingState.reset(new LinkingState()); mLinkingState.reset(new LinkingState());
mLinkingState->context = context; mLinkingState->context = context;
mLinkingState->linkingFromBinary = false; mLinkingState->linkingFromBinary = false;
mLinkingState->programHash = programHash; mLinkingState->programHash = programHash;
mLinkingState->linkEvent = mProgram->link(context, *resources, mInfoLog); mLinkingState->linkEvent = mProgram->link(context, *resources, mInfoLog);
mLinkingState->resources = std::move(resources); mLinkingState->resources = std::move(resources);
mLinkResolved = false; mLinkResolved = false;
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1447,8 +1448,8 @@ void Program::resolveLinkImpl(const Context *context) ...@@ -1447,8 +1448,8 @@ void Program::resolveLinkImpl(const Context *context)
angle::Result result = mLinkingState->linkEvent->wait(context); angle::Result result = mLinkingState->linkEvent->wait(context);
mLinked = result == angle::Result::Continue; mLinked = result == angle::Result::Continue;
mLinkResolved = true; mLinkResolved = true;
std::unique_ptr<LinkingState> linkingState = std::move(mLinkingState); std::unique_ptr<LinkingState> linkingState = std::move(mLinkingState);
if (!mLinked) if (!mLinked)
{ {
...@@ -4016,7 +4017,7 @@ bool Program::linkOutputVariables(const Caps &caps, ...@@ -4016,7 +4017,7 @@ bool Program::linkOutputVariables(const Caps &caps,
// GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
// structures, so we may use getBasicTypeElementCount(). // structures, so we may use getBasicTypeElementCount().
unsigned int elementCount = outputVariable.getBasicTypeElementCount(); unsigned int elementCount = outputVariable.getBasicTypeElementCount();
if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations, if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex)) outputVariableIndex))
{ {
...@@ -4785,6 +4786,11 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4785,6 +4786,11 @@ angle::Result Program::deserialize(const Context *context,
"Too many shader types"); "Too many shader types");
mState.mLinkedShaderStages = ShaderBitSet(stream.readInt<uint8_t>()); mState.mLinkedShaderStages = ShaderBitSet(stream.readInt<uint8_t>());
if (!mState.mAttachedShaders[ShaderType::Compute])
{
mState.updateTransformFeedbackStrides();
}
postResolveLink(context); postResolveLink(context);
return angle::Result::Continue; return angle::Result::Continue;
...@@ -4792,11 +4798,6 @@ angle::Result Program::deserialize(const Context *context, ...@@ -4792,11 +4798,6 @@ angle::Result Program::deserialize(const Context *context,
void Program::postResolveLink(const gl::Context *context) void Program::postResolveLink(const gl::Context *context)
{ {
if (!mState.mAttachedShaders[ShaderType::Compute])
{
mState.updateTransformFeedbackStrides();
}
mState.updateActiveSamplers(); mState.updateActiveSamplers();
mState.updateActiveImages(); mState.updateActiveImages();
......
...@@ -253,6 +253,7 @@ struct TransformFeedbackVarying : public sh::Varying ...@@ -253,6 +253,7 @@ struct TransformFeedbackVarying : public sh::Varying
interpolation = parent.interpolation; interpolation = parent.interpolation;
isInvariant = parent.isInvariant; isInvariant = parent.isInvariant;
name = parent.name + "." + name; name = parent.name + "." + name;
mappedName = parent.mappedName + "." + mappedName;
} }
std::string nameWithArrayIndex() const std::string nameWithArrayIndex() const
...@@ -347,6 +348,11 @@ class ProgramState final : angle::NonCopyable ...@@ -347,6 +348,11 @@ class ProgramState final : angle::NonCopyable
{ {
return mLinkedTransformFeedbackVaryings; return mLinkedTransformFeedbackVaryings;
} }
const std::vector<GLsizei> &getTransformFeedbackStrides() const
{
return mTransformFeedbackStrides;
}
size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); }
const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
{ {
return mAtomicCounterBuffers; return mAtomicCounterBuffers;
...@@ -897,7 +903,6 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -897,7 +903,6 @@ class Program final : angle::NonCopyable, public LabeledObject
// Writes a program's binary to the output memory buffer. // Writes a program's binary to the output memory buffer.
void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const; void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const;
private: private:
struct LinkingState; struct LinkingState;
......
...@@ -79,12 +79,7 @@ QueryType Query::getType() const ...@@ -79,12 +79,7 @@ QueryType Query::getType() const
return mQuery->getType(); return mQuery->getType();
} }
rx::QueryImpl *Query::getImplementation() rx::QueryImpl *Query::getImplementation() const
{
return mQuery;
}
const rx::QueryImpl *Query::getImplementation() const
{ {
return mQuery; return mQuery;
} }
......
...@@ -47,8 +47,7 @@ class Query final : public RefCountObject, public LabeledObject ...@@ -47,8 +47,7 @@ class Query final : public RefCountObject, public LabeledObject
QueryType getType() const; QueryType getType() const;
rx::QueryImpl *getImplementation(); rx::QueryImpl *getImplementation() const;
const rx::QueryImpl *getImplementation() const;
private: private:
rx::QueryImpl *mQuery; rx::QueryImpl *mQuery;
......
...@@ -69,6 +69,21 @@ const std::vector<OffsetBindingPointer<Buffer>> &TransformFeedbackState::getInde ...@@ -69,6 +69,21 @@ const std::vector<OffsetBindingPointer<Buffer>> &TransformFeedbackState::getInde
return mIndexedBuffers; return mIndexedBuffers;
} }
GLsizeiptr TransformFeedbackState::getPrimitivesDrawn() const
{
switch (mPrimitiveMode)
{
case gl::PrimitiveMode::Points:
return mVerticesDrawn;
case gl::PrimitiveMode::Lines:
return mVerticesDrawn / 2;
case gl::PrimitiveMode::Triangles:
return mVerticesDrawn / 3;
default:
return 0;
}
}
TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps) TransformFeedback::TransformFeedback(rx::GLImplFactory *implFactory, GLuint id, const Caps &caps)
: RefCountObject(id), : RefCountObject(id),
mState(caps.maxTransformFeedbackSeparateAttributes), mState(caps.maxTransformFeedbackSeparateAttributes),
...@@ -289,12 +304,7 @@ bool TransformFeedback::buffersBoundForOtherUse() const ...@@ -289,12 +304,7 @@ bool TransformFeedback::buffersBoundForOtherUse() const
return false; return false;
} }
rx::TransformFeedbackImpl *TransformFeedback::getImplementation() rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
{
return mImplementation;
}
const rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
{ {
return mImplementation; return mImplementation;
} }
......
...@@ -38,6 +38,8 @@ class TransformFeedbackState final : angle::NonCopyable ...@@ -38,6 +38,8 @@ class TransformFeedbackState final : angle::NonCopyable
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t idx) const; const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t idx) const;
const std::vector<OffsetBindingPointer<Buffer>> &getIndexedBuffers() const; const std::vector<OffsetBindingPointer<Buffer>> &getIndexedBuffers() const;
const Program *getBoundProgram() const { return mProgram; } const Program *getBoundProgram() const { return mProgram; }
GLsizeiptr getVerticesDrawn() const { return mVerticesDrawn; }
GLsizeiptr getPrimitivesDrawn() const;
private: private:
friend class TransformFeedback; friend class TransformFeedback;
...@@ -93,13 +95,15 @@ class TransformFeedback final : public RefCountObject, public LabeledObject ...@@ -93,13 +95,15 @@ class TransformFeedback final : public RefCountObject, public LabeledObject
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t index) const; const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t index) const;
size_t getIndexedBufferCount() const; size_t getIndexedBufferCount() const;
GLsizeiptr getVerticesDrawn() const { return mState.getVerticesDrawn(); }
GLsizeiptr getPrimitivesDrawn() const { return mState.getPrimitivesDrawn(); }
// Returns true if any buffer bound to this object is also bound to another target. // Returns true if any buffer bound to this object is also bound to another target.
bool buffersBoundForOtherUse() const; bool buffersBoundForOtherUse() const;
angle::Result detachBuffer(const Context *context, GLuint bufferName); angle::Result detachBuffer(const Context *context, GLuint bufferName);
rx::TransformFeedbackImpl *getImplementation(); rx::TransformFeedbackImpl *getImplementation() const;
const rx::TransformFeedbackImpl *getImplementation() const;
void onBindingChanged(const Context *context, bool bound); void onBindingChanged(const Context *context, bool bound);
......
...@@ -471,6 +471,10 @@ using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>; ...@@ -471,6 +471,10 @@ using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>;
using SupportedSampleSet = std::set<GLuint>; using SupportedSampleSet = std::set<GLuint>;
template <typename T>
using TransformFeedbackBuffersArray =
std::array<T, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>;
// OffsetBindingPointer.getSize() returns the size specified by the user, which may be larger than // OffsetBindingPointer.getSize() returns the size specified by the user, which may be larger than
// the size of the bound buffer. This function reduces the returned size to fit the bound buffer if // the size of the bound buffer. This function reduces the returned size to fit the bound buffer if
// necessary. Returns 0 if no buffer is bound or if integer overflow occurs. // necessary. Returns 0 if no buffer is bound or if integer overflow occurs.
......
...@@ -88,6 +88,17 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType, ...@@ -88,6 +88,17 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType,
UNREACHABLE(); UNREACHABLE();
return "Query"; return "Query";
} }
case CommandGraphResourceType::EmulatedQuery:
switch (function)
{
case CommandGraphNodeFunction::BeginTransformFeedbackQuery:
return "BeginTransformFeedbackQuery";
case CommandGraphNodeFunction::EndTransformFeedbackQuery:
return "EndTransformFeedbackQuery";
default:
UNREACHABLE();
return "EmulatedQuery";
}
case CommandGraphResourceType::FenceSync: case CommandGraphResourceType::FenceSync:
switch (function) switch (function)
{ {
...@@ -442,7 +453,9 @@ void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIn ...@@ -442,7 +453,9 @@ void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIn
{ {
ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery || ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
mFunction == CommandGraphNodeFunction::EndQuery || mFunction == CommandGraphNodeFunction::EndQuery ||
mFunction == CommandGraphNodeFunction::WriteTimestamp); mFunction == CommandGraphNodeFunction::WriteTimestamp ||
mFunction == CommandGraphNodeFunction::BeginTransformFeedbackQuery ||
mFunction == CommandGraphNodeFunction::EndTransformFeedbackQuery);
mQueryPool = queryPool->getHandle(); mQueryPool = queryPool->getHandle();
mQueryIndex = queryIndex; mQueryIndex = queryIndex;
} }
...@@ -585,6 +598,15 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, ...@@ -585,6 +598,15 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
break; break;
case CommandGraphNodeFunction::BeginTransformFeedbackQuery:
// Unless using VK_EXT_transform_feedback (not implemented currently), there's nothing
// to do.
break;
case CommandGraphNodeFunction::EndTransformFeedbackQuery:
// Same as BeginTransformFeedbackQuery.
break;
case CommandGraphNodeFunction::SetFenceSync: case CommandGraphNodeFunction::SetFenceSync:
ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid()); ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
ASSERT(mFenceSyncEvent != VK_NULL_HANDLE); ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
...@@ -911,6 +933,18 @@ void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryInde ...@@ -911,6 +933,18 @@ void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryInde
newNode->setQueryPool(queryPool, queryIndex); newNode->setQueryPool(queryPool, queryIndex);
} }
void CommandGraph::beginTransformFeedbackEmulatedQuery()
{
allocateBarrierNode(CommandGraphNodeFunction::BeginTransformFeedbackQuery,
CommandGraphResourceType::EmulatedQuery, 0);
}
void CommandGraph::endTransformFeedbackEmulatedQuery()
{
allocateBarrierNode(CommandGraphNodeFunction::EndTransformFeedbackQuery,
CommandGraphResourceType::EmulatedQuery, 0);
}
void CommandGraph::setFenceSync(const vk::Event &event) void CommandGraph::setFenceSync(const vk::Event &event)
{ {
CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::SetFenceSync, CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::SetFenceSync,
...@@ -973,6 +1007,7 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const ...@@ -973,6 +1007,7 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
int imageIDCounter = 1; int imageIDCounter = 1;
int queryIDCounter = 1; int queryIDCounter = 1;
int fenceIDCounter = 1; int fenceIDCounter = 1;
int xfbIDCounter = 1;
out << "digraph {" << std::endl; out << "digraph {" << std::endl;
...@@ -1049,6 +1084,9 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const ...@@ -1049,6 +1084,9 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
case CommandGraphResourceType::FenceSync: case CommandGraphResourceType::FenceSync:
id = fenceIDCounter++; id = fenceIDCounter++;
break; break;
case CommandGraphResourceType::EmulatedQuery:
id = xfbIDCounter++;
break;
default: default:
UNREACHABLE(); UNREACHABLE();
break; break;
......
...@@ -32,6 +32,9 @@ enum class CommandGraphResourceType ...@@ -32,6 +32,9 @@ enum class CommandGraphResourceType
Framebuffer, Framebuffer,
Image, Image,
Query, Query,
// Transform feedback queries could be handled entirely on the CPU (if not using
// VK_EXT_transform_feedback), but still need to generate a command graph barrier node.
EmulatedQuery,
FenceSync, FenceSync,
DebugMarker, DebugMarker,
HostAvailabilityOperation, HostAvailabilityOperation,
...@@ -45,6 +48,8 @@ enum class CommandGraphNodeFunction ...@@ -45,6 +48,8 @@ enum class CommandGraphNodeFunction
BeginQuery, BeginQuery,
EndQuery, EndQuery,
WriteTimestamp, WriteTimestamp,
BeginTransformFeedbackQuery,
EndTransformFeedbackQuery,
SetFenceSync, SetFenceSync,
WaitFenceSync, WaitFenceSync,
InsertDebugMarker, InsertDebugMarker,
...@@ -446,6 +451,8 @@ class CommandGraph final : angle::NonCopyable ...@@ -446,6 +451,8 @@ class CommandGraph final : angle::NonCopyable
void beginQuery(const QueryPool *queryPool, uint32_t queryIndex); void beginQuery(const QueryPool *queryPool, uint32_t queryIndex);
void endQuery(const QueryPool *queryPool, uint32_t queryIndex); void endQuery(const QueryPool *queryPool, uint32_t queryIndex);
void writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex); void writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex);
void beginTransformFeedbackEmulatedQuery();
void endTransformFeedbackEmulatedQuery();
// GLsync and EGLSync: // GLsync and EGLSync:
void setFenceSync(const vk::Event &event); void setFenceSync(const vk::Event &event);
void waitFenceSync(const vk::Event &event); void waitFenceSync(const vk::Event &event);
......
...@@ -174,6 +174,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -174,6 +174,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mProgram(nullptr), mProgram(nullptr),
mLastIndexBufferOffset(0), mLastIndexBufferOffset(0),
mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum), mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
mXfbBaseVertex(0),
mClearColorMask(kAllColorChannelsMask), mClearColorMask(kAllColorChannelsMask),
mFlipYForCurrentSurface(false), mFlipYForCurrentSurface(false),
mIsAnyHostVisibleBufferWritten(false), mIsAnyHostVisibleBufferWritten(false),
...@@ -201,6 +202,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -201,6 +202,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mNewCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS); mNewCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER); mNewCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS); mNewCommandBufferDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS); mNewCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] = &ContextVk::handleDirtyDefaultAttribs; mDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] = &ContextVk::handleDirtyDefaultAttribs;
...@@ -210,6 +212,8 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk ...@@ -210,6 +212,8 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer; mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer;
mDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = &ContextVk::handleDirtyDriverUniforms; mDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = &ContextVk::handleDirtyDriverUniforms;
mDirtyBitHandlers[DIRTY_BIT_UNIFORM_BUFFERS] = &ContextVk::handleDirtyUniformBuffers; mDirtyBitHandlers[DIRTY_BIT_UNIFORM_BUFFERS] = &ContextVk::handleDirtyUniformBuffers;
mDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
&ContextVk::handleDirtyTransformFeedbackBuffers;
mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets; mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
mDirtyBits = mNewCommandBufferDirtyBits; mDirtyBits = mNewCommandBufferDirtyBits;
...@@ -451,6 +455,13 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, ...@@ -451,6 +455,13 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS); mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
} }
// Update transform feedback offsets on every draw call.
if (mState.isTransformFeedbackActiveUnpaused())
{
mXfbBaseVertex = firstVertex;
invalidateDriverUniforms();
}
DirtyBits dirtyBits = mDirtyBits & dirtyBitMask; DirtyBits dirtyBits = mDirtyBits & dirtyBitMask;
if (dirtyBits.none()) if (dirtyBits.none())
...@@ -645,6 +656,17 @@ angle::Result ContextVk::handleDirtyUniformBuffers(const gl::Context *context, ...@@ -645,6 +656,17 @@ angle::Result ContextVk::handleDirtyUniformBuffers(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ContextVk::handleDirtyTransformFeedbackBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
if (mProgram->hasTransformFeedbackOutput() && mState.isTransformFeedbackActive())
{
ANGLE_TRY(mProgram->updateTransformFeedbackDescriptorSet(
this, mDrawFramebuffer->getFramebuffer()));
}
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyDescriptorSets(const gl::Context *context, angle::Result ContextVk::handleDirtyDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
...@@ -1595,6 +1617,7 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -1595,6 +1617,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
glState.getDrawFramebuffer()); glState.getDrawFramebuffer());
mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
mDrawFramebuffer->getRenderPassDesc()); mDrawFramebuffer->getRenderPassDesc());
invalidateCurrentTransformFeedbackBuffers();
break; break;
} }
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING: case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
...@@ -1632,6 +1655,7 @@ angle::Result ContextVk::syncState(const gl::Context *context, ...@@ -1632,6 +1655,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
invalidateCurrentTextures(); invalidateCurrentTextures();
break; break;
case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING: case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
// Nothing to do.
break; break;
case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING: case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
break; break;
...@@ -1879,6 +1903,17 @@ void ContextVk::onFramebufferChange(const vk::RenderPassDesc &renderPassDesc) ...@@ -1879,6 +1903,17 @@ void ContextVk::onFramebufferChange(const vk::RenderPassDesc &renderPassDesc)
mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, renderPassDesc); mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition, renderPassDesc);
} }
void ContextVk::invalidateCurrentTransformFeedbackBuffers()
{
mDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
void ContextVk::onTransformFeedbackPauseResume()
{
invalidateDriverUniforms();
}
angle::Result ContextVk::dispatchCompute(const gl::Context *context, angle::Result ContextVk::dispatchCompute(const gl::Context *context,
GLuint numGroupsX, GLuint numGroupsX,
GLuint numGroupsY, GLuint numGroupsY,
...@@ -1951,6 +1986,8 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context, ...@@ -1951,6 +1986,8 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
mDriverUniformsDynamicOffset = static_cast<uint32_t>(offset); mDriverUniformsDynamicOffset = static_cast<uint32_t>(offset);
uint32_t xfbActiveUnpaused = mState.isTransformFeedbackActiveUnpaused();
float depthRangeNear = mState.getNearPlane(); float depthRangeNear = mState.getNearPlane();
float depthRangeFar = mState.getFarPlane(); float depthRangeFar = mState.getFarPlane();
float depthRangeDiff = depthRangeFar - depthRangeNear; float depthRangeDiff = depthRangeFar - depthRangeNear;
...@@ -1963,9 +2000,19 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context, ...@@ -1963,9 +2000,19 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
halfRenderAreaHeight, halfRenderAreaHeight,
scaleY, scaleY,
-scaleY, -scaleY,
0.0f, xfbActiveUnpaused,
{},
{depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}}; {depthRangeNear, depthRangeFar, depthRangeDiff, 0.0f}};
if (xfbActiveUnpaused)
{
TransformFeedbackVk *transformFeedbackVk =
vk::GetImpl(mState.getCurrentTransformFeedback());
transformFeedbackVk->getBufferOffsets(this, mState.getProgram()->getState(), mXfbBaseVertex,
driverUniforms->xfbBufferOffsets.data(),
driverUniforms->xfbBufferOffsets.size());
}
ANGLE_TRY(mDriverUniformsBuffer.flush(this)); ANGLE_TRY(mDriverUniformsBuffer.flush(this));
if (newBuffer) if (newBuffer)
......
...@@ -215,6 +215,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff ...@@ -215,6 +215,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
void onFramebufferChange(const vk::RenderPassDesc &renderPassDesc); void onFramebufferChange(const vk::RenderPassDesc &renderPassDesc);
void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; } void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; }
void invalidateCurrentTransformFeedbackBuffers();
void onTransformFeedbackPauseResume();
vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType); vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType);
const VkClearValue &getClearColorValue() const; const VkClearValue &getClearColorValue() const;
...@@ -324,6 +327,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff ...@@ -324,6 +327,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
DIRTY_BIT_INDEX_BUFFER, DIRTY_BIT_INDEX_BUFFER,
DIRTY_BIT_DRIVER_UNIFORMS, DIRTY_BIT_DRIVER_UNIFORMS,
DIRTY_BIT_UNIFORM_BUFFERS, DIRTY_BIT_UNIFORM_BUFFERS,
DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
DIRTY_BIT_DESCRIPTOR_SETS, DIRTY_BIT_DESCRIPTOR_SETS,
DIRTY_BIT_MAX, DIRTY_BIT_MAX,
}; };
...@@ -391,6 +395,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff ...@@ -391,6 +395,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyUniformBuffers(const gl::Context *context, angle::Result handleDirtyUniformBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyTransformFeedbackBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyDescriptorSets(const gl::Context *context, angle::Result handleDirtyDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
...@@ -442,6 +448,12 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff ...@@ -442,6 +448,12 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
const GLvoid *mLastIndexBufferOffset; const GLvoid *mLastIndexBufferOffset;
gl::DrawElementsType mCurrentDrawElementsType; gl::DrawElementsType mCurrentDrawElementsType;
// Cache the current draw call's firstVertex to be passed to
// TransformFeedbackVk::getBufferOffsets. Unfortunately, gl_BaseVertex support in Vulkan is
// not yet ubiquitous, which would have otherwise removed the need for this value to be passed
// as a uniform.
GLint mXfbBaseVertex;
// Cached clear value/mask for color and depth/stencil. // Cached clear value/mask for color and depth/stencil.
VkClearValue mClearColorValue; VkClearValue mClearColorValue;
VkClearValue mClearDepthStencilValue; VkClearValue mClearDepthStencilValue;
...@@ -467,7 +479,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff ...@@ -467,7 +479,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
float halfRenderAreaHeight; float halfRenderAreaHeight;
float viewportYScale; float viewportYScale;
float negViewportYScale; float negViewportYScale;
float padding; uint32_t xfbActiveUnpaused;
std::array<int32_t, 4> xfbBufferOffsets;
// We'll use x, y, z for near / far / diff respectively. // We'll use x, y, z for near / far / diff respectively.
std::array<float, 4> depthRange; std::array<float, 4> depthRange;
......
...@@ -236,12 +236,12 @@ IntermediateShaderSource::IntermediateShaderSource(const std::string &source) ...@@ -236,12 +236,12 @@ IntermediateShaderSource::IntermediateShaderSource(const std::string &source)
else if (source.compare(cur, ConstStrLen(kXfbDeclMarkerBegin), kXfbDeclMarkerBegin) == 0) else if (source.compare(cur, ConstStrLen(kXfbDeclMarkerBegin), kXfbDeclMarkerBegin) == 0)
{ {
cur += ConstStrLen(kXfbDeclMarkerBegin); cur += ConstStrLen(kXfbDeclMarkerBegin);
addTransformFeedbackOutputBlock(); addTransformFeedbackDeclarationBlock();
} }
else if (source.compare(cur, ConstStrLen(kXfbOutMarkerBegin), kXfbOutMarkerBegin) == 0) else if (source.compare(cur, ConstStrLen(kXfbOutMarkerBegin), kXfbOutMarkerBegin) == 0)
{ {
cur += ConstStrLen(kXfbOutMarkerBegin); cur += ConstStrLen(kXfbOutMarkerBegin);
addTransformFeedbackDeclarationBlock(); addTransformFeedbackOutputBlock();
} }
else else
{ {
...@@ -366,6 +366,103 @@ uint32_t CountExplicitOutputs(OutputIter outputsBegin, ...@@ -366,6 +366,103 @@ uint32_t CountExplicitOutputs(OutputIter outputsBegin,
return std::accumulate(outputsBegin, outputsEnd, 0, reduce); return std::accumulate(outputsBegin, outputsEnd, 0, reduce);
} }
std::string GenerateTransformFeedbackVaryingOutput(const gl::TransformFeedbackVarying &varying,
const gl::UniformTypeInfo &info,
size_t strideBytes,
size_t offset,
const std::string &bufferIndex)
{
std::ostringstream result;
ASSERT(strideBytes % 4 == 0);
size_t stride = strideBytes / 4;
const size_t arrayIndexStart = varying.arrayIndex == GL_INVALID_INDEX ? 0 : varying.arrayIndex;
const size_t arrayIndexEnd = arrayIndexStart + varying.size();
for (size_t arrayIndex = arrayIndexStart; arrayIndex < arrayIndexEnd; ++arrayIndex)
{
for (int col = 0; col < info.columnCount; ++col)
{
for (int row = 0; row < info.rowCount; ++row)
{
result << "xfbOut" << bufferIndex << "[ANGLEUniforms.xfbBufferOffsets["
<< bufferIndex << "] + gl_VertexIndex * " << stride << " + " << offset
<< "] = " << info.glslAsFloat << "(" << varying.mappedName;
if (varying.isArray())
{
result << "[" << arrayIndex << "]";
}
if (info.columnCount > 1)
{
result << "[" << col << "]";
}
if (info.rowCount > 1)
{
result << "[" << row << "]";
}
result << ");\n";
++offset;
}
}
}
return result.str();
}
void GenerateTransformFeedbackOutputs(const gl::ProgramState &programState,
IntermediateShaderSource *vertexShader)
{
const std::vector<gl::TransformFeedbackVarying> &varyings =
programState.getLinkedTransformFeedbackVaryings();
const std::vector<GLsizei> &bufferStrides = programState.getTransformFeedbackStrides();
const bool isInterleaved =
programState.getTransformFeedbackBufferMode() == GL_INTERLEAVED_ATTRIBS;
const size_t bufferCount = isInterleaved ? 1 : varyings.size();
const std::string xfbSet = Str(kUniformsAndXfbDescriptorSetIndex);
std::vector<std::string> xfbIndices(bufferCount);
std::string xfbDecl;
for (size_t bufferIndex = 0; bufferIndex < bufferCount; ++bufferIndex)
{
const std::string xfbBinding = Str(kXfbBindingIndexStart + bufferIndex);
xfbIndices[bufferIndex] = Str(bufferIndex);
xfbDecl += "layout(set = " + xfbSet + ", binding = " + xfbBinding + ") buffer xfbBuffer" +
xfbIndices[bufferIndex] + " { float xfbOut" + xfbIndices[bufferIndex] +
"[]; };\n";
}
std::string xfbOut = "if (ANGLEUniforms.xfbActiveUnpaused != 0)\n{\n";
size_t outputOffset = 0;
for (size_t varyingIndex = 0; varyingIndex < varyings.size(); ++varyingIndex)
{
const size_t bufferIndex = isInterleaved ? 0 : varyingIndex;
const gl::TransformFeedbackVarying &varying = varyings[varyingIndex];
// For every varying, output to the respective buffer packed. If interleaved, the output is
// always to the same buffer, but at different offsets.
const gl::UniformTypeInfo &info = gl::GetUniformTypeInfo(varying.type);
xfbOut += GenerateTransformFeedbackVaryingOutput(varying, info, bufferStrides[bufferIndex],
outputOffset, xfbIndices[bufferIndex]);
if (isInterleaved)
{
outputOffset += info.columnCount * info.rowCount * varying.size();
}
}
xfbOut += "}\n";
vertexShader->insertTransformFeedbackDeclaration(std::move(xfbDecl));
vertexShader->insertTransformFeedbackOutput(std::move(xfbOut));
}
} // anonymous namespace } // anonymous namespace
// static // static
...@@ -525,7 +622,7 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState, ...@@ -525,7 +622,7 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
// See corresponding code in OutputVulkanGLSL.cpp. // See corresponding code in OutputVulkanGLSL.cpp.
const std::string driverUniformsDescriptorSet = const std::string driverUniformsDescriptorSet =
"set = " + Str(kDriverUniformsDescriptorSetIndex); "set = " + Str(kDriverUniformsDescriptorSetIndex);
const std::string uniformsDescriptorSet = "set = " + Str(kUniformsDescriptorSetIndex); const std::string uniformsDescriptorSet = "set = " + Str(kUniformsAndXfbDescriptorSetIndex);
const std::string uniformBlocksDescriptorSet = "set = " + Str(kUniformBlockDescriptorSetIndex); const std::string uniformBlocksDescriptorSet = "set = " + Str(kUniformBlockDescriptorSetIndex);
const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex); const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
...@@ -643,10 +740,15 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState, ...@@ -643,10 +740,15 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
fragmentSource.insertLayoutSpecifier(kVaryingName, layout); fragmentSource.insertLayoutSpecifier(kVaryingName, layout);
// Write transform feedback output code. // Write transform feedback output code.
// TODO(syoussefi): support transform feedback. http://anglebug.com/3205 if (programState.getLinkedTransformFeedbackVaryings().empty())
ASSERT(programState.getLinkedTransformFeedbackVaryings().size() == 0); {
vertexSource.insertTransformFeedbackDeclaration(""); vertexSource.insertTransformFeedbackDeclaration("");
vertexSource.insertTransformFeedbackOutput(""); vertexSource.insertTransformFeedbackOutput("");
}
else
{
GenerateTransformFeedbackOutputs(programState, &vertexSource);
}
vertexSource.insertQualifierSpecifier(kVaryingName, "out"); vertexSource.insertQualifierSpecifier(kVaryingName, "out");
fragmentSource.insertQualifierSpecifier(kVaryingName, "in"); fragmentSource.insertQualifierSpecifier(kVaryingName, "in");
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h" #include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx namespace rx
...@@ -109,6 +110,8 @@ class ProgramVk : public ProgramImpl ...@@ -109,6 +110,8 @@ class ProgramVk : public ProgramImpl
vk::FramebufferHelper *framebuffer); vk::FramebufferHelper *framebuffer);
angle::Result updateUniformBuffersDescriptorSet(ContextVk *contextVk, angle::Result updateUniformBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer); vk::FramebufferHelper *framebuffer);
angle::Result updateTransformFeedbackDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer); angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer);
...@@ -119,6 +122,10 @@ class ProgramVk : public ProgramImpl ...@@ -119,6 +122,10 @@ class ProgramVk : public ProgramImpl
bool hasTextures() const { return !mState.getSamplerBindings().empty(); } bool hasTextures() const { return !mState.getSamplerBindings().empty(); }
bool hasUniformBuffers() const { return !mState.getUniformBlocks().empty(); } bool hasUniformBuffers() const { return !mState.getUniformBlocks().empty(); }
bool hasTransformFeedbackOutput() const
{
return !mState.getLinkedTransformFeedbackVaryings().empty();
}
bool dirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); } bool dirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); }
...@@ -159,7 +166,8 @@ class ProgramVk : public ProgramImpl ...@@ -159,7 +166,8 @@ class ProgramVk : public ProgramImpl
bool *newPoolAllocatedOut); bool *newPoolAllocatedOut);
angle::Result initDefaultUniformBlocks(const gl::Context *glContext); angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
angle::Result updateDefaultUniformsDescriptorSet(ContextVk *contextVk); void updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);
template <class T> template <class T>
void getUniformImpl(GLint location, T *v, GLenum entryPointType) const; void getUniformImpl(GLint location, T *v, GLenum entryPointType) const;
...@@ -219,7 +227,11 @@ class ProgramVk : public ProgramImpl ...@@ -219,7 +227,11 @@ class ProgramVk : public ProgramImpl
gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks; gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
gl::ShaderBitSet mDefaultUniformBlocksDirty; gl::ShaderBitSet mDefaultUniformBlocksDirty;
gl::ShaderMap<uint32_t> mUniformBlocksOffsets;
static constexpr uint32_t kShaderTypeMin = static_cast<uint32_t>(gl::kGLES2ShaderTypeMin);
static constexpr uint32_t kShaderTypeMax = static_cast<uint32_t>(gl::kGLES2ShaderTypeMax);
static constexpr uint32_t kShaderTypeCount = kShaderTypeMax - kShaderTypeMin + 1;
std::array<uint32_t, kShaderTypeCount> mDynamicBufferOffsets;
// This is a special "empty" placeholder buffer for when a shader has no uniforms. // This is a special "empty" placeholder buffer for when a shader has no uniforms.
// It is necessary because we want to keep a compatible pipeline layout in all cases, // It is necessary because we want to keep a compatible pipeline layout in all cases,
......
...@@ -9,25 +9,34 @@ ...@@ -9,25 +9,34 @@
#include "libANGLE/renderer/vulkan/QueryVk.h" #include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/TransformFeedback.h"
#include "libANGLE/renderer/vulkan/ContextVk.h" #include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h" #include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "common/debug.h" #include "common/debug.h"
namespace rx namespace rx
{ {
QueryVk::QueryVk(gl::QueryType type) : QueryImpl(type), mCachedResult(0), mCachedResultValid(false) QueryVk::QueryVk(gl::QueryType type)
: QueryImpl(type),
mTransformFeedbackPrimitivesDrawn(0),
mCachedResult(0),
mCachedResultValid(false)
{} {}
QueryVk::~QueryVk() = default; QueryVk::~QueryVk() = default;
void QueryVk::onDestroy(const gl::Context *context) void QueryVk::onDestroy(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(getType()); if (getType() != gl::QueryType::TransformFeedbackPrimitivesWritten)
queryPool->freeQuery(contextVk, &mQueryHelper); {
queryPool->freeQuery(contextVk, &mQueryHelperTimeElapsedBegin); vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(getType());
queryPool->freeQuery(contextVk, &mQueryHelper);
queryPool->freeQuery(contextVk, &mQueryHelperTimeElapsedBegin);
}
} }
angle::Result QueryVk::begin(const gl::Context *context) angle::Result QueryVk::begin(const gl::Context *context)
...@@ -36,6 +45,14 @@ angle::Result QueryVk::begin(const gl::Context *context) ...@@ -36,6 +45,14 @@ angle::Result QueryVk::begin(const gl::Context *context)
mCachedResultValid = false; mCachedResultValid = false;
// Transform feedback query is a handled by a CPU-calculated value when emulated.
if (getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
{
mTransformFeedbackPrimitivesDrawn = 0;
contextVk->getCommandGraph()->beginTransformFeedbackEmulatedQuery();
return angle::Result::Continue;
}
if (!mQueryHelper.getQueryPool()) if (!mQueryHelper.getQueryPool())
{ {
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper)); ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
...@@ -64,7 +81,22 @@ angle::Result QueryVk::end(const gl::Context *context) ...@@ -64,7 +81,22 @@ angle::Result QueryVk::end(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
if (getType() == gl::QueryType::TimeElapsed) if (getType() == gl::QueryType::TransformFeedbackPrimitivesWritten)
{
mCachedResult = mTransformFeedbackPrimitivesDrawn;
// There could be transform feedback in progress, so add the primitives drawn so far from
// the current transform feedback object.
gl::TransformFeedback *transformFeedback =
context->getState().getCurrentTransformFeedback();
if (transformFeedback)
{
mCachedResult += transformFeedback->getPrimitivesDrawn();
}
mCachedResultValid = true;
contextVk->getCommandGraph()->endTransformFeedbackEmulatedQuery();
}
else if (getType() == gl::QueryType::TimeElapsed)
{ {
mQueryHelper.writeTimestamp(contextVk); mQueryHelper.writeTimestamp(contextVk);
} }
...@@ -217,4 +249,12 @@ angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *avail ...@@ -217,4 +249,12 @@ angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *avail
return angle::Result::Continue; return angle::Result::Continue;
} }
void QueryVk::onTransformFeedbackEnd(const gl::Context *context)
{
gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
ASSERT(transformFeedback);
mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn();
}
} // namespace rx } // namespace rx
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
namespace rx namespace rx
{ {
class TransformFeedbackVk;
class QueryVk : public QueryImpl class QueryVk : public QueryImpl
{ {
...@@ -33,13 +34,18 @@ class QueryVk : public QueryImpl ...@@ -33,13 +34,18 @@ class QueryVk : public QueryImpl
angle::Result getResult(const gl::Context *context, GLuint64 *params) override; angle::Result getResult(const gl::Context *context, GLuint64 *params) override;
angle::Result isResultAvailable(const gl::Context *context, bool *available) override; angle::Result isResultAvailable(const gl::Context *context, bool *available) override;
void onTransformFeedbackEnd(const gl::Context *context);
private: private:
angle::Result getResult(const gl::Context *context, bool wait); angle::Result getResult(const gl::Context *context, bool wait);
// Used for AnySamples, AnySamplesConservative, Timestamp and TimeElapsed (end) // Used for AnySamples, AnySamplesConservative, Timestamp and TimeElapsed (end).
vk::QueryHelper mQueryHelper; vk::QueryHelper mQueryHelper;
// An additional query used for TimeElapsed (begin), as it is implemented using Timestamp // An additional query used for TimeElapsed (begin), as it is implemented using Timestamp.
vk::QueryHelper mQueryHelperTimeElapsedBegin; vk::QueryHelper mQueryHelperTimeElapsedBegin;
// Used with TransformFeedbackPrimitivesWritten when transform feedback is emulated.
size_t mTransformFeedbackPrimitivesDrawn;
uint64_t mCachedResult; uint64_t mCachedResult;
bool mCachedResultValid; bool mCachedResultValid;
}; };
......
...@@ -951,6 +951,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -951,6 +951,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend; enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend;
enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess; enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess;
enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy; enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy;
enabledFeatures.features.vertexPipelineStoresAndAtomics =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics;
if (!vk::CommandBuffer::ExecutesInline()) if (!vk::CommandBuffer::ExecutesInline())
{ {
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries; enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
...@@ -1128,6 +1130,14 @@ gl::Version RendererVk::getMaxSupportedESVersion() const ...@@ -1128,6 +1130,14 @@ 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
// 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)
{
maxVersion = std::max(maxVersion, gl::Version(2, 0));
}
return maxVersion; return maxVersion;
} }
...@@ -1202,6 +1212,13 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames) ...@@ -1202,6 +1212,13 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
mFeatures.supportsShaderStencilExport.enabled = true; mFeatures.supportsShaderStencilExport.enabled = true;
} }
// 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
if (mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
{
mFeatures.emulateTransformFeedback.enabled = true;
}
if (IsLinux() && IsIntel(mPhysicalDeviceProperties.vendorID)) if (IsLinux() && IsIntel(mPhysicalDeviceProperties.vendorID))
{ {
mFeatures.disableFifoPresentMode.enabled = true; mFeatures.disableFifoPresentMode.enabled = true;
......
...@@ -11,9 +11,19 @@ ...@@ -11,9 +11,19 @@
#define LIBANGLE_RENDERER_VULKAN_TRANSFORMFEEDBACKVK_H_ #define LIBANGLE_RENDERER_VULKAN_TRANSFORMFEEDBACKVK_H_
#include "libANGLE/renderer/TransformFeedbackImpl.h" #include "libANGLE/renderer/TransformFeedbackImpl.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace gl
{
class ProgramState;
} // namespace gl
namespace rx namespace rx
{ {
namespace vk
{
class DescriptorSetLayoutDesc;
}
class TransformFeedbackVk : public TransformFeedbackImpl class TransformFeedbackVk : public TransformFeedbackImpl
{ {
...@@ -29,6 +39,37 @@ class TransformFeedbackVk : public TransformFeedbackImpl ...@@ -29,6 +39,37 @@ class TransformFeedbackVk : public TransformFeedbackImpl
angle::Result bindIndexedBuffer(const gl::Context *context, angle::Result bindIndexedBuffer(const gl::Context *context,
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,
vk::DescriptorSetLayoutDesc *descSetLayoutOut) const;
void addFramebufferDependency(ContextVk *contextVk,
const gl::ProgramState &programState,
vk::FramebufferHelper *framebuffer) const;
void updateDescriptorSet(ContextVk *contextVk,
const gl::ProgramState &programState,
VkDescriptorSet descSet,
uint32_t bindingOffset) const;
void getBufferOffsets(ContextVk *contextVk,
const gl::ProgramState &programState,
GLint drawCallFirstVertex,
int32_t *offsetsOut,
size_t offsetsSize) const;
private:
void onBeginEnd(const gl::Context *context);
// 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;
}; };
} // namespace rx } // namespace rx
......
...@@ -891,16 +891,17 @@ class PipelineLayoutCache final : angle::NonCopyable ...@@ -891,16 +891,17 @@ class PipelineLayoutCache final : angle::NonCopyable
// //
// The set/binding assignment is done as following: // The set/binding assignment is done as following:
// //
// - Set 0 contains the ANGLE driver uniforms at binding 0. Note that driver uniforms are updated // - Set 0 contains uniform blocks created to encompass default uniforms. Bindings 0 and 1
// correspond to default uniforms in the vertex and fragment shaders respectively. Additionally,
// transform feedback buffers are bound from binding 2 and up.
// - Set 1 contains all textures.
// - Set 2 contains all uniform blocks.
// - Set 3 contains the ANGLE driver uniforms at binding 0. Note that driver uniforms are updated
// only under rare circumstances, such as viewport or depth range change. However, there is only // only under rare circumstances, such as viewport or depth range change. However, there is only
// one binding in this set. // one binding in this set.
// - Set 1 contains uniform blocks created to encompass default uniforms. Bindings 0 and 1
// correspond to default uniforms in the vertex and fragment shaders respectively.
// - Set 2 contains all textures.
// - Set 3 contains all uniform blocks.
// Uniforms set index: // Uniforms set index:
constexpr uint32_t kUniformsDescriptorSetIndex = 0; constexpr uint32_t kUniformsAndXfbDescriptorSetIndex = 0;
// Textures set index: // Textures set index:
constexpr uint32_t kTextureDescriptorSetIndex = 1; constexpr uint32_t kTextureDescriptorSetIndex = 1;
// Uniform blocks set index: // Uniform blocks set index:
...@@ -914,6 +915,8 @@ constexpr uint32_t kReservedDriverUniformBindingCount = 1; ...@@ -914,6 +915,8 @@ constexpr uint32_t kReservedDriverUniformBindingCount = 1;
constexpr uint32_t kVertexUniformsBindingIndex = 0; constexpr uint32_t kVertexUniformsBindingIndex = 0;
// Binding index for default uniforms in the fragment shader: // Binding index for default uniforms in the fragment shader:
constexpr uint32_t kFragmentUniformsBindingIndex = 1; constexpr uint32_t kFragmentUniformsBindingIndex = 1;
// Binding index start for transform feedback buffers:
constexpr uint32_t kXfbBindingIndexStart = 2;
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_ #endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
...@@ -225,14 +225,21 @@ void RendererVk::ensureCapsInitialized() const ...@@ -225,14 +225,21 @@ void RendererVk::ensureCapsInitialized() const
// The gles2.0 section 2.10 states that "gl_Position is not a varying variable and does // The gles2.0 section 2.10 states that "gl_Position is not a varying variable and does
// not count against this limit.", but the Vulkan spec has no such mention in its Built-in // not count against this limit.", but the Vulkan spec has no such mention in its Built-in
// vars section. It is implicit that we need to actually reserve it for Vulkan in that case. // vars section. It is implicit that we need to actually reserve it for Vulkan in that case.
// TODO(lucferron): AMD has a weird behavior when we edge toward the maximum number of varyings //
// and can often crash. Reserving an additional varying just for them bringing the total to 2. // Note: AMD has a weird behavior when we edge toward the maximum number of varyings and can
// http://anglebug.com/2483 // often crash. Reserving an additional varying just for them bringing the total to 2.
constexpr GLint kReservedVaryingCount = 2; constexpr GLint kReservedVaryingCount = 2;
mNativeCaps.maxVaryingVectors = mNativeCaps.maxVaryingVectors =
(mPhysicalDeviceProperties.limits.maxVertexOutputComponents / 4) - kReservedVaryingCount; (mPhysicalDeviceProperties.limits.maxVertexOutputComponents / 4) - kReservedVaryingCount;
mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxVaryingVectors * 4; mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxVaryingVectors * 4;
mNativeCaps.maxTransformFeedbackInterleavedComponents =
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS;
mNativeCaps.maxTransformFeedbackSeparateAttributes =
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS;
mNativeCaps.maxTransformFeedbackSeparateComponents =
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
const VkPhysicalDeviceLimits &limits = mPhysicalDeviceProperties.limits; const VkPhysicalDeviceLimits &limits = mPhysicalDeviceProperties.limits;
const uint32_t sampleCounts = limits.framebufferColorSampleCounts & const uint32_t sampleCounts = limits.framebufferColorSampleCounts &
limits.framebufferDepthSampleCounts & limits.framebufferDepthSampleCounts &
......
...@@ -26,9 +26,11 @@ ...@@ -26,9 +26,11 @@
PROC(Context) \ PROC(Context) \
PROC(Framebuffer) \ PROC(Framebuffer) \
PROC(MemoryObject) \ PROC(MemoryObject) \
PROC(Query) \
PROC(Program) \ PROC(Program) \
PROC(Semaphore) \ PROC(Semaphore) \
PROC(Texture) \ PROC(Texture) \
PROC(TransformFeedback) \
PROC(VertexArray) PROC(VertexArray)
#define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ; #define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
......
...@@ -537,7 +537,6 @@ ...@@ -537,7 +537,6 @@
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_fragment_input_components = SKIP 2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_fragment_input_components = SKIP
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_program_texel_offset = SKIP 2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_program_texel_offset = SKIP
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.min_program_texel_offset = SKIP 2950 VULKAN : dEQP-GLES3.functional.implementation_limits.min_program_texel_offset = SKIP
2950 VULKAN : dEQP-GLES3.functional.implementation_limits.max_transform_feedback_* = SKIP
// 3D texture (anglebug.com/3188), 2D array (anglebug.com/3189): // 3D texture (anglebug.com/3188), 2D array (anglebug.com/3189):
3189 VULKAN : dEQP-GLES3.functional.shaders.texture_functions.texturegrad.sampler2darrayshadow_vertex = SKIP 3189 VULKAN : dEQP-GLES3.functional.shaders.texture_functions.texturegrad.sampler2darrayshadow_vertex = SKIP
...@@ -680,22 +679,6 @@ ...@@ -680,22 +679,6 @@
3198 VULKAN : dEQP-GLES3.functional.uniform_api.value.* = SKIP 3198 VULKAN : dEQP-GLES3.functional.uniform_api.value.* = SKIP
3198 VULKAN : dEQP-GLES3.functional.uniform_api.random.* = SKIP 3198 VULKAN : dEQP-GLES3.functional.uniform_api.random.* = SKIP
// Transform feedback:
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.uniform_block_binding = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.bind_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.begin_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.pause_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.resume_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.shader.end_transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.transform_feedback.* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.boolean.transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.integers.max_transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.integers.transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.indexed.transform_feedback_* = FAIL
3205 VULKAN : dEQP-GLES3.functional.state_query.shader.transform_feedback = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.vertex_array.draw_range_elements = FAIL
3205 VULKAN : dEQP-GLES3.functional.negative_api.vertex_array.draw_range_elements_incomplete_primitive = FAIL
// Flat shading: // Flat shading:
3430 VULKAN : dEQP-GLES3.functional.rasterization.flatshading.* = FAIL 3430 VULKAN : dEQP-GLES3.functional.rasterization.flatshading.* = FAIL
3430 VULKAN : dEQP-GLES3.functional.shaders.linkage.varying.basic_types.u* = FAIL 3430 VULKAN : dEQP-GLES3.functional.shaders.linkage.varying.basic_types.u* = FAIL
......
...@@ -49,8 +49,8 @@ ...@@ -49,8 +49,8 @@
3457 VULKAN : KHR-GLES3.packed_pixels.pbo_rectangle.depth* = SKIP 3457 VULKAN : KHR-GLES3.packed_pixels.pbo_rectangle.depth* = SKIP
3457 VULKAN : KHR-GLES3.packed_depth_stencil.* = SKIP 3457 VULKAN : KHR-GLES3.packed_depth_stencil.* = SKIP
// CopyTexImage conversion bugs. // CopyTexImage conversion missing 2D Array and 3D texture support.
3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = FAIL 3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = SKIP
// Require 3D textures. // Require 3D textures.
3188 VULKAN : KHR-GLES3.packed_pixels.varied_rectangle.* = SKIP 3188 VULKAN : KHR-GLES3.packed_pixels.varied_rectangle.* = SKIP
......
...@@ -105,7 +105,7 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport) ...@@ -105,7 +105,7 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport)
drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
// End the query and transform feedkback // End the query and transform feedback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback(); glEndTransformFeedback();
...@@ -236,7 +236,7 @@ TEST_P(TransformFeedbackTest, RecordAndDraw) ...@@ -236,7 +236,7 @@ TEST_P(TransformFeedbackTest, RecordAndDraw)
glDisableVertexAttribArray(positionLocation); glDisableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr); glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
// End the query and transform feedkback // End the query and transform feedback
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
glEndTransformFeedback(); glEndTransformFeedback();
...@@ -1644,8 +1644,16 @@ TEST_P(TransformFeedbackTest, EndWithDifferentProgramContextSwitch) ...@@ -1644,8 +1644,16 @@ TEST_P(TransformFeedbackTest, EndWithDifferentProgramContextSwitch)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(TransformFeedbackTest,
ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ES3_D3D11(),
ES3_OPENGL(),
ES3_OPENGLES(),
ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest,
ES3_D3D11(),
ES3_OPENGL(),
ES3_OPENGLES(),
ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(TransformFeedbackTestES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES()); ANGLE_INSTANTIATE_TEST(TransformFeedbackTestES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
} // anonymous namespace } // anonymous namespace
...@@ -63,7 +63,7 @@ class VulkanUniformUpdatesTest : public ANGLETest ...@@ -63,7 +63,7 @@ class VulkanUniformUpdatesTest : public ANGLETest
// Force a small limit on the max sets per pool to more easily trigger a new allocation. // Force a small limit on the max sets per pool to more easily trigger a new allocation.
rx::vk::DynamicDescriptorPool *uniformPool = rx::vk::DynamicDescriptorPool *uniformPool =
programVk->getDynamicDescriptorPool(rx::kUniformsDescriptorSetIndex); programVk->getDynamicDescriptorPool(rx::kUniformsAndXfbDescriptorSetIndex);
uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting); uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
rx::GetUniformBufferDescriptorCount()}; rx::GetUniformBufferDescriptorCount()};
......
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