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
"supports_shader_stencil_export", FeatureCategory::VulkanFeatures,
"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
Feature disableFifoPresentMode = {
"disable_fifo_present_mode", FeatureCategory::VulkanWorkarounds,
......
......@@ -466,7 +466,7 @@
"proc table:src/libGLESv2/proc_table_autogen.cpp":
"e82a9970d6059a7c8b562726e3f219a4",
"uniform type:src/common/gen_uniform_type_table.py":
"9dd389f2b5793ba635169d61cef2dde9",
"a741cc301b1617ab0e4d29b35f1d3b96",
"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)
}} // 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};"""
......@@ -183,15 +183,15 @@ def get_components(uniform_type):
def get_component_size(uniform_type):
component_type = get_component_type(uniform_type)
if (component_type) == "GL_BOOL":
if component_type == "GL_BOOL":
return "sizeof(GLint)"
elif (component_type) == "GL_FLOAT":
elif component_type == "GL_FLOAT":
return "sizeof(GLfloat)"
elif (component_type) == "GL_INT":
elif component_type == "GL_INT":
return "sizeof(GLint)"
elif (component_type) == "GL_UNSIGNED_INT":
elif component_type == "GL_UNSIGNED_INT":
return "sizeof(GLuint)"
elif (component_type) == "GL_NONE":
elif component_type == "GL_NONE":
return "0"
else:
raise "Invalid component type: " + component_type
......@@ -217,6 +217,22 @@ def get_is_image(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):
return type_info_data_template.format(
type=uniform_type,
......@@ -233,7 +249,8 @@ def gen_type_info(uniform_type):
external_size=get_external_size(uniform_type),
is_sampler=get_is_sampler(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):
......
......@@ -139,7 +139,8 @@ struct UniformTypeInfo final : angle::NonCopyable
size_t externalSize,
bool isSampler,
bool isMatrixType,
bool isImageType);
bool isImageType,
const char *glslAsFloat);
GLenum type;
GLenum componentType;
......@@ -156,6 +157,7 @@ struct UniformTypeInfo final : angle::NonCopyable
bool isSampler;
bool isMatrixType;
bool isImageType;
const char *glslAsFloat;
};
inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
......@@ -172,7 +174,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
size_t externalSize,
bool isSampler,
bool isMatrixType,
bool isImageType)
bool isImageType,
const char *glslAsFloat)
: type(type),
componentType(componentType),
textureType(textureType),
......@@ -187,7 +190,8 @@ inline constexpr UniformTypeInfo::UniformTypeInfo(GLenum type,
externalSize(externalSize),
isSampler(isSampler),
isMatrixType(isMatrixType),
isImageType(isImageType)
isImageType(isImageType),
glslAsFloat(glslAsFloat)
{}
const UniformTypeInfo &GetUniformTypeInfo(GLenum uniformType);
......
......@@ -157,12 +157,14 @@ constexpr const char kViewport[] = "viewport";
constexpr const char kHalfRenderAreaHeight[] = "halfRenderAreaHeight";
constexpr const char kViewportYScale[] = "viewportYScale";
constexpr const char kNegViewportYScale[] = "negViewportYScale";
constexpr const char kXfbActiveUnpaused[] = "xfbActiveUnpaused";
constexpr const char kXfbBufferOffsets[] = "xfbBufferOffsets";
constexpr const char kDepthRange[] = "depthRange";
constexpr size_t kNumDriverUniforms = 6;
constexpr size_t kNumDriverUniforms = 7;
constexpr std::array<const char *, kNumDriverUniforms> kDriverUniformNames = {
{kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, "padding",
kDepthRange}};
{kViewport, kHalfRenderAreaHeight, kViewportYScale, kNegViewportYScale, kXfbActiveUnpaused,
kXfbBufferOffsets, kDepthRange}};
template <TBasicType BasicType = EbtFloat, unsigned char PrimarySize = 1>
TIntermConstantUnion *CreateBasicConstant(float value)
......@@ -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(EbtUInt),
new TType(EbtInt, 4),
emulatedDepthRangeType,
}};
......
......@@ -44,6 +44,7 @@ class BufferState final : angle::NonCopyable
GLint64 getMapOffset() const { return mMapOffset; }
GLint64 getMapLength() const { return mMapLength; }
GLint64 getSize() const { return mSize; }
bool isBoundForTransformFeedback() const { return mTransformFeedbackIndexedBindingCount != 0; }
private:
friend class Buffer;
......
......@@ -41,7 +41,11 @@ enum
// GL_EXT_geometry_shader increases the minimum value of GL_MAX_UNIFORM_BUFFER_BINDINGS to 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.
IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS = 4,
......
......@@ -3301,6 +3301,13 @@ void Context::initCaps()
LimitCap(&mState.mCaps.maxVertexOutputComponents, 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.
LimitCap(&mState.mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
LimitCap(&mState.mCaps.maxShaderTextureImageUnits[ShaderType::Vertex],
......
......@@ -1423,15 +1423,16 @@ angle::Result Program::link(const Context *context)
}
gatherTransformFeedbackVaryings(mergedVaryings);
mState.updateTransformFeedbackStrides();
}
mLinkingState.reset(new LinkingState());
mLinkingState->context = context;
mLinkingState->context = context;
mLinkingState->linkingFromBinary = false;
mLinkingState->programHash = programHash;
mLinkingState->linkEvent = mProgram->link(context, *resources, mInfoLog);
mLinkingState->resources = std::move(resources);
mLinkResolved = false;
mLinkingState->programHash = programHash;
mLinkingState->linkEvent = mProgram->link(context, *resources, mInfoLog);
mLinkingState->resources = std::move(resources);
mLinkResolved = false;
return angle::Result::Continue;
}
......@@ -1447,8 +1448,8 @@ void Program::resolveLinkImpl(const Context *context)
angle::Result result = mLinkingState->linkEvent->wait(context);
mLinked = result == angle::Result::Continue;
mLinkResolved = true;
mLinked = result == angle::Result::Continue;
mLinkResolved = true;
std::unique_ptr<LinkingState> linkingState = std::move(mLinkingState);
if (!mLinked)
{
......@@ -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
// structures, so we may use getBasicTypeElementCount().
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex))
{
......@@ -4785,6 +4786,11 @@ angle::Result Program::deserialize(const Context *context,
"Too many shader types");
mState.mLinkedShaderStages = ShaderBitSet(stream.readInt<uint8_t>());
if (!mState.mAttachedShaders[ShaderType::Compute])
{
mState.updateTransformFeedbackStrides();
}
postResolveLink(context);
return angle::Result::Continue;
......@@ -4792,11 +4798,6 @@ angle::Result Program::deserialize(const Context *context,
void Program::postResolveLink(const gl::Context *context)
{
if (!mState.mAttachedShaders[ShaderType::Compute])
{
mState.updateTransformFeedbackStrides();
}
mState.updateActiveSamplers();
mState.updateActiveImages();
......
......@@ -253,6 +253,7 @@ struct TransformFeedbackVarying : public sh::Varying
interpolation = parent.interpolation;
isInvariant = parent.isInvariant;
name = parent.name + "." + name;
mappedName = parent.mappedName + "." + mappedName;
}
std::string nameWithArrayIndex() const
......@@ -347,6 +348,11 @@ class ProgramState final : angle::NonCopyable
{
return mLinkedTransformFeedbackVaryings;
}
const std::vector<GLsizei> &getTransformFeedbackStrides() const
{
return mTransformFeedbackStrides;
}
size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); }
const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
{
return mAtomicCounterBuffers;
......@@ -897,7 +903,6 @@ class Program final : angle::NonCopyable, public LabeledObject
// Writes a program's binary to the output memory buffer.
void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const;
private:
struct LinkingState;
......
......@@ -79,12 +79,7 @@ QueryType Query::getType() const
return mQuery->getType();
}
rx::QueryImpl *Query::getImplementation()
{
return mQuery;
}
const rx::QueryImpl *Query::getImplementation() const
rx::QueryImpl *Query::getImplementation() const
{
return mQuery;
}
......
......@@ -47,8 +47,7 @@ class Query final : public RefCountObject, public LabeledObject
QueryType getType() const;
rx::QueryImpl *getImplementation();
const rx::QueryImpl *getImplementation() const;
rx::QueryImpl *getImplementation() const;
private:
rx::QueryImpl *mQuery;
......
......@@ -69,6 +69,21 @@ const std::vector<OffsetBindingPointer<Buffer>> &TransformFeedbackState::getInde
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)
: RefCountObject(id),
mState(caps.maxTransformFeedbackSeparateAttributes),
......@@ -289,12 +304,7 @@ bool TransformFeedback::buffersBoundForOtherUse() const
return false;
}
rx::TransformFeedbackImpl *TransformFeedback::getImplementation()
{
return mImplementation;
}
const rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
rx::TransformFeedbackImpl *TransformFeedback::getImplementation() const
{
return mImplementation;
}
......
......@@ -38,6 +38,8 @@ class TransformFeedbackState final : angle::NonCopyable
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t idx) const;
const std::vector<OffsetBindingPointer<Buffer>> &getIndexedBuffers() const;
const Program *getBoundProgram() const { return mProgram; }
GLsizeiptr getVerticesDrawn() const { return mVerticesDrawn; }
GLsizeiptr getPrimitivesDrawn() const;
private:
friend class TransformFeedback;
......@@ -93,13 +95,15 @@ class TransformFeedback final : public RefCountObject, public LabeledObject
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t index) 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.
bool buffersBoundForOtherUse() const;
angle::Result detachBuffer(const Context *context, GLuint bufferName);
rx::TransformFeedbackImpl *getImplementation();
const rx::TransformFeedbackImpl *getImplementation() const;
rx::TransformFeedbackImpl *getImplementation() const;
void onBindingChanged(const Context *context, bool bound);
......
......@@ -471,6 +471,10 @@ using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>;
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
// 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.
......
......@@ -88,6 +88,17 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType,
UNREACHABLE();
return "Query";
}
case CommandGraphResourceType::EmulatedQuery:
switch (function)
{
case CommandGraphNodeFunction::BeginTransformFeedbackQuery:
return "BeginTransformFeedbackQuery";
case CommandGraphNodeFunction::EndTransformFeedbackQuery:
return "EndTransformFeedbackQuery";
default:
UNREACHABLE();
return "EmulatedQuery";
}
case CommandGraphResourceType::FenceSync:
switch (function)
{
......@@ -442,7 +453,9 @@ void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIn
{
ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
mFunction == CommandGraphNodeFunction::EndQuery ||
mFunction == CommandGraphNodeFunction::WriteTimestamp);
mFunction == CommandGraphNodeFunction::WriteTimestamp ||
mFunction == CommandGraphNodeFunction::BeginTransformFeedbackQuery ||
mFunction == CommandGraphNodeFunction::EndTransformFeedbackQuery);
mQueryPool = queryPool->getHandle();
mQueryIndex = queryIndex;
}
......@@ -585,6 +598,15 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
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:
ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
......@@ -911,6 +933,18 @@ void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryInde
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)
{
CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::SetFenceSync,
......@@ -973,6 +1007,7 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
int imageIDCounter = 1;
int queryIDCounter = 1;
int fenceIDCounter = 1;
int xfbIDCounter = 1;
out << "digraph {" << std::endl;
......@@ -1049,6 +1084,9 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
case CommandGraphResourceType::FenceSync:
id = fenceIDCounter++;
break;
case CommandGraphResourceType::EmulatedQuery:
id = xfbIDCounter++;
break;
default:
UNREACHABLE();
break;
......
......@@ -32,6 +32,9 @@ enum class CommandGraphResourceType
Framebuffer,
Image,
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,
DebugMarker,
HostAvailabilityOperation,
......@@ -45,6 +48,8 @@ enum class CommandGraphNodeFunction
BeginQuery,
EndQuery,
WriteTimestamp,
BeginTransformFeedbackQuery,
EndTransformFeedbackQuery,
SetFenceSync,
WaitFenceSync,
InsertDebugMarker,
......@@ -446,6 +451,8 @@ class CommandGraph final : angle::NonCopyable
void beginQuery(const QueryPool *queryPool, uint32_t queryIndex);
void endQuery(const QueryPool *queryPool, uint32_t queryIndex);
void writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex);
void beginTransformFeedbackEmulatedQuery();
void endTransformFeedbackEmulatedQuery();
// GLsync and EGLSync:
void setFenceSync(const vk::Event &event);
void waitFenceSync(const vk::Event &event);
......
......@@ -174,6 +174,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mProgram(nullptr),
mLastIndexBufferOffset(0),
mCurrentDrawElementsType(gl::DrawElementsType::InvalidEnum),
mXfbBaseVertex(0),
mClearColorMask(kAllColorChannelsMask),
mFlipYForCurrentSurface(false),
mIsAnyHostVisibleBufferWritten(false),
......@@ -201,6 +202,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mNewCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] = &ContextVk::handleDirtyDefaultAttribs;
......@@ -210,6 +212,8 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer;
mDirtyBitHandlers[DIRTY_BIT_DRIVER_UNIFORMS] = &ContextVk::handleDirtyDriverUniforms;
mDirtyBitHandlers[DIRTY_BIT_UNIFORM_BUFFERS] = &ContextVk::handleDirtyUniformBuffers;
mDirtyBitHandlers[DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS] =
&ContextVk::handleDirtyTransformFeedbackBuffers;
mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
mDirtyBits = mNewCommandBufferDirtyBits;
......@@ -451,6 +455,13 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
// Update transform feedback offsets on every draw call.
if (mState.isTransformFeedbackActiveUnpaused())
{
mXfbBaseVertex = firstVertex;
invalidateDriverUniforms();
}
DirtyBits dirtyBits = mDirtyBits & dirtyBitMask;
if (dirtyBits.none())
......@@ -645,6 +656,17 @@ angle::Result ContextVk::handleDirtyUniformBuffers(const gl::Context *context,
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,
vk::CommandBuffer *commandBuffer)
{
......@@ -1595,6 +1617,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
glState.getDrawFramebuffer());
mGraphicsPipelineDesc->updateRenderPassDesc(&mGraphicsPipelineTransition,
mDrawFramebuffer->getRenderPassDesc());
invalidateCurrentTransformFeedbackBuffers();
break;
}
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
......@@ -1632,6 +1655,7 @@ angle::Result ContextVk::syncState(const gl::Context *context,
invalidateCurrentTextures();
break;
case gl::State::DIRTY_BIT_TRANSFORM_FEEDBACK_BINDING:
// Nothing to do.
break;
case gl::State::DIRTY_BIT_SHADER_STORAGE_BUFFER_BINDING:
break;
......@@ -1879,6 +1903,17 @@ void ContextVk::onFramebufferChange(const vk::RenderPassDesc &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,
GLuint numGroupsX,
GLuint numGroupsY,
......@@ -1951,6 +1986,8 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
mDriverUniformsDynamicOffset = static_cast<uint32_t>(offset);
uint32_t xfbActiveUnpaused = mState.isTransformFeedbackActiveUnpaused();
float depthRangeNear = mState.getNearPlane();
float depthRangeFar = mState.getFarPlane();
float depthRangeDiff = depthRangeFar - depthRangeNear;
......@@ -1963,9 +2000,19 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
halfRenderAreaHeight,
scaleY,
-scaleY,
0.0f,
xfbActiveUnpaused,
{},
{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));
if (newBuffer)
......
......@@ -215,6 +215,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
void onFramebufferChange(const vk::RenderPassDesc &renderPassDesc);
void onHostVisibleBufferWrite() { mIsAnyHostVisibleBufferWritten = true; }
void invalidateCurrentTransformFeedbackBuffers();
void onTransformFeedbackPauseResume();
vk::DynamicQueryPool *getQueryPool(gl::QueryType queryType);
const VkClearValue &getClearColorValue() const;
......@@ -324,6 +327,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
DIRTY_BIT_INDEX_BUFFER,
DIRTY_BIT_DRIVER_UNIFORMS,
DIRTY_BIT_UNIFORM_BUFFERS,
DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS,
DIRTY_BIT_DESCRIPTOR_SETS,
DIRTY_BIT_MAX,
};
......@@ -391,6 +395,8 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyUniformBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyTransformFeedbackBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
......@@ -442,6 +448,12 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
const GLvoid *mLastIndexBufferOffset;
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.
VkClearValue mClearColorValue;
VkClearValue mClearDepthStencilValue;
......@@ -467,7 +479,9 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::CommandBuff
float halfRenderAreaHeight;
float viewportYScale;
float negViewportYScale;
float padding;
uint32_t xfbActiveUnpaused;
std::array<int32_t, 4> xfbBufferOffsets;
// We'll use x, y, z for near / far / diff respectively.
std::array<float, 4> depthRange;
......
......@@ -236,12 +236,12 @@ IntermediateShaderSource::IntermediateShaderSource(const std::string &source)
else if (source.compare(cur, ConstStrLen(kXfbDeclMarkerBegin), kXfbDeclMarkerBegin) == 0)
{
cur += ConstStrLen(kXfbDeclMarkerBegin);
addTransformFeedbackOutputBlock();
addTransformFeedbackDeclarationBlock();
}
else if (source.compare(cur, ConstStrLen(kXfbOutMarkerBegin), kXfbOutMarkerBegin) == 0)
{
cur += ConstStrLen(kXfbOutMarkerBegin);
addTransformFeedbackDeclarationBlock();
addTransformFeedbackOutputBlock();
}
else
{
......@@ -366,6 +366,103 @@ uint32_t CountExplicitOutputs(OutputIter outputsBegin,
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
// static
......@@ -525,7 +622,7 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
// See corresponding code in OutputVulkanGLSL.cpp.
const std::string driverUniformsDescriptorSet =
"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 texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
......@@ -643,10 +740,15 @@ void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
fragmentSource.insertLayoutSpecifier(kVaryingName, layout);
// Write transform feedback output code.
// TODO(syoussefi): support transform feedback. http://anglebug.com/3205
ASSERT(programState.getLinkedTransformFeedbackVaryings().size() == 0);
vertexSource.insertTransformFeedbackDeclaration("");
vertexSource.insertTransformFeedbackOutput("");
if (programState.getLinkedTransformFeedbackVaryings().empty())
{
vertexSource.insertTransformFeedbackDeclaration("");
vertexSource.insertTransformFeedbackOutput("");
}
else
{
GenerateTransformFeedbackOutputs(programState, &vertexSource);
}
vertexSource.insertQualifierSpecifier(kVaryingName, "out");
fragmentSource.insertQualifierSpecifier(kVaryingName, "in");
......
......@@ -16,6 +16,7 @@
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx
......@@ -109,6 +110,8 @@ class ProgramVk : public ProgramImpl
vk::FramebufferHelper *framebuffer);
angle::Result updateUniformBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateTransformFeedbackDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer);
......@@ -119,6 +122,10 @@ class ProgramVk : public ProgramImpl
bool hasTextures() const { return !mState.getSamplerBindings().empty(); }
bool hasUniformBuffers() const { return !mState.getUniformBlocks().empty(); }
bool hasTransformFeedbackOutput() const
{
return !mState.getLinkedTransformFeedbackVaryings().empty();
}
bool dirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); }
......@@ -159,7 +166,8 @@ class ProgramVk : public ProgramImpl
bool *newPoolAllocatedOut);
angle::Result initDefaultUniformBlocks(const gl::Context *glContext);
angle::Result updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);
template <class T>
void getUniformImpl(GLint location, T *v, GLenum entryPointType) const;
......@@ -219,7 +227,11 @@ class ProgramVk : public ProgramImpl
gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
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.
// It is necessary because we want to keep a compatible pipeline layout in all cases,
......
......@@ -9,25 +9,34 @@
#include "libANGLE/renderer/vulkan/QueryVk.h"
#include "libANGLE/Context.h"
#include "libANGLE/TransformFeedback.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/TransformFeedbackVk.h"
#include "common/debug.h"
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;
void QueryVk::onDestroy(const gl::Context *context)
{
ContextVk *contextVk = vk::GetImpl(context);
vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(getType());
queryPool->freeQuery(contextVk, &mQueryHelper);
queryPool->freeQuery(contextVk, &mQueryHelperTimeElapsedBegin);
ContextVk *contextVk = vk::GetImpl(context);
if (getType() != gl::QueryType::TransformFeedbackPrimitivesWritten)
{
vk::DynamicQueryPool *queryPool = contextVk->getQueryPool(getType());
queryPool->freeQuery(contextVk, &mQueryHelper);
queryPool->freeQuery(contextVk, &mQueryHelperTimeElapsedBegin);
}
}
angle::Result QueryVk::begin(const gl::Context *context)
......@@ -36,6 +45,14 @@ angle::Result QueryVk::begin(const gl::Context *context)
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())
{
ANGLE_TRY(contextVk->getQueryPool(getType())->allocateQuery(contextVk, &mQueryHelper));
......@@ -64,7 +81,22 @@ angle::Result QueryVk::end(const gl::Context *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);
}
......@@ -217,4 +249,12 @@ angle::Result QueryVk::isResultAvailable(const gl::Context *context, bool *avail
return angle::Result::Continue;
}
void QueryVk::onTransformFeedbackEnd(const gl::Context *context)
{
gl::TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback();
ASSERT(transformFeedback);
mTransformFeedbackPrimitivesDrawn += transformFeedback->getPrimitivesDrawn();
}
} // namespace rx
......@@ -15,6 +15,7 @@
namespace rx
{
class TransformFeedbackVk;
class QueryVk : public QueryImpl
{
......@@ -33,13 +34,18 @@ class QueryVk : public QueryImpl
angle::Result getResult(const gl::Context *context, GLuint64 *params) override;
angle::Result isResultAvailable(const gl::Context *context, bool *available) override;
void onTransformFeedbackEnd(const gl::Context *context);
private:
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;
// 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;
// Used with TransformFeedbackPrimitivesWritten when transform feedback is emulated.
size_t mTransformFeedbackPrimitivesDrawn;
uint64_t mCachedResult;
bool mCachedResultValid;
};
......
......@@ -951,6 +951,8 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend;
enabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess;
enabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy;
enabledFeatures.features.vertexPipelineStoresAndAtomics =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics;
if (!vk::CommandBuffer::ExecutesInline())
{
enabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries;
......@@ -1128,6 +1130,14 @@ 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)
{
maxVersion = std::max(maxVersion, gl::Version(2, 0));
}
return maxVersion;
}
......@@ -1202,6 +1212,13 @@ void RendererVk::initFeatures(const ExtensionNameList &deviceExtensionNames)
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))
{
mFeatures.disableFifoPresentMode.enabled = true;
......
......@@ -11,9 +11,19 @@
#define LIBANGLE_RENDERER_VULKAN_TRANSFORMFEEDBACKVK_H_
#include "libANGLE/renderer/TransformFeedbackImpl.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace gl
{
class ProgramState;
} // namespace gl
namespace rx
{
namespace vk
{
class DescriptorSetLayoutDesc;
}
class TransformFeedbackVk : public TransformFeedbackImpl
{
......@@ -29,6 +39,37 @@ class TransformFeedbackVk : public TransformFeedbackImpl
angle::Result bindIndexedBuffer(const gl::Context *context,
size_t index,
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
......
......@@ -891,16 +891,17 @@ class PipelineLayoutCache final : angle::NonCopyable
//
// 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
// 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:
constexpr uint32_t kUniformsDescriptorSetIndex = 0;
constexpr uint32_t kUniformsAndXfbDescriptorSetIndex = 0;
// Textures set index:
constexpr uint32_t kTextureDescriptorSetIndex = 1;
// Uniform blocks set index:
......@@ -914,6 +915,8 @@ constexpr uint32_t kReservedDriverUniformBindingCount = 1;
constexpr uint32_t kVertexUniformsBindingIndex = 0;
// Binding index for default uniforms in the fragment shader:
constexpr uint32_t kFragmentUniformsBindingIndex = 1;
// Binding index start for transform feedback buffers:
constexpr uint32_t kXfbBindingIndexStart = 2;
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_VK_CACHE_UTILS_H_
......@@ -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
// 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.
// 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.
// http://anglebug.com/2483
//
// Note: 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.
constexpr GLint kReservedVaryingCount = 2;
mNativeCaps.maxVaryingVectors =
(mPhysicalDeviceProperties.limits.maxVertexOutputComponents / 4) - kReservedVaryingCount;
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 uint32_t sampleCounts = limits.framebufferColorSampleCounts &
limits.framebufferDepthSampleCounts &
......
......@@ -26,9 +26,11 @@
PROC(Context) \
PROC(Framebuffer) \
PROC(MemoryObject) \
PROC(Query) \
PROC(Program) \
PROC(Semaphore) \
PROC(Texture) \
PROC(TransformFeedback) \
PROC(VertexArray)
#define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
......
......@@ -537,7 +537,6 @@
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.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):
3189 VULKAN : dEQP-GLES3.functional.shaders.texture_functions.texturegrad.sampler2darrayshadow_vertex = SKIP
......@@ -680,22 +679,6 @@
3198 VULKAN : dEQP-GLES3.functional.uniform_api.value.* = 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:
3430 VULKAN : dEQP-GLES3.functional.rasterization.flatshading.* = FAIL
3430 VULKAN : dEQP-GLES3.functional.shaders.linkage.varying.basic_types.u* = FAIL
......
......@@ -49,8 +49,8 @@
3457 VULKAN : KHR-GLES3.packed_pixels.pbo_rectangle.depth* = SKIP
3457 VULKAN : KHR-GLES3.packed_depth_stencil.* = SKIP
// CopyTexImage conversion bugs.
3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = FAIL
// CopyTexImage conversion missing 2D Array and 3D texture support.
3458 VULKAN : KHR-GLES3.copy_tex_image_conversions.required.* = SKIP
// Require 3D textures.
3188 VULKAN : KHR-GLES3.packed_pixels.varied_rectangle.* = SKIP
......
......@@ -105,7 +105,7 @@ TEST_P(TransformFeedbackTest, ZeroSizedViewport)
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);
glEndTransformFeedback();
......@@ -236,7 +236,7 @@ TEST_P(TransformFeedbackTest, RecordAndDraw)
glDisableVertexAttribArray(positionLocation);
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);
glEndTransformFeedback();
......@@ -1644,8 +1644,16 @@ TEST_P(TransformFeedbackTest, EndWithDifferentProgramContextSwitch)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TransformFeedbackLifetimeTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest,
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());
} // anonymous namespace
......@@ -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.
rx::vk::DynamicDescriptorPool *uniformPool =
programVk->getDynamicDescriptorPool(rx::kUniformsDescriptorSetIndex);
programVk->getDynamicDescriptorPool(rx::kUniformsAndXfbDescriptorSetIndex);
uniformPool->setMaxSetsPerPoolForTesting(kMaxSetsForTesting);
VkDescriptorPoolSize uniformSetSize = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
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