Commit c405ae71 by Brandon Jones Committed by Commit Bot

Optimize Vertex Shader Attribute Type Validition

Improves ValidateVertexShaderAttributeTypeMatch by storing vertex attributes types into masks for quick comparisons when needed. This shows 2% improvement to glDrawElements for the aquarium workload. BUG=angleproject:2202 Change-Id: I87fa3d30c3d8cdba6dfd936cd1a41fd27b1c6b77 Reviewed-on: https://chromium-review.googlesource.com/814795 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 91586494
...@@ -174,6 +174,8 @@ ERRMSG(UniformSizeMismatch, "Uniform size does not match uniform method."); ...@@ -174,6 +174,8 @@ ERRMSG(UniformSizeMismatch, "Uniform size does not match uniform method.");
ERRMSG(UnknownParameter, "Unknown parameter value."); ERRMSG(UnknownParameter, "Unknown parameter value.");
ERRMSG(VertexArrayNoBuffer, "An enabled vertex array has no buffer."); ERRMSG(VertexArrayNoBuffer, "An enabled vertex array has no buffer.");
ERRMSG(VertexArrayNoBufferPointer, "An enabled vertex array has no buffer and no pointer."); ERRMSG(VertexArrayNoBufferPointer, "An enabled vertex array has no buffer and no pointer.");
ERRMSG(VertexShaderTypeMismatch,
"Vertex shader input type does not match the type of the bound vertex attribute.")
ERRMSG(ViewportNegativeSize, "Viewport size cannot be negative."); ERRMSG(ViewportNegativeSize, "Viewport size cannot be negative.");
ERRMSG(Webgl2NameLengthLimitExceeded, "Location lengths must not be greater than 1024 characters."); ERRMSG(Webgl2NameLengthLimitExceeded, "Location lengths must not be greater than 1024 characters.");
ERRMSG(WebglBindAttribLocationReservedPrefix, ERRMSG(WebglBindAttribLocationReservedPrefix,
......
...@@ -915,7 +915,7 @@ GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const ...@@ -915,7 +915,7 @@ GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
} }
} }
DrawBufferTypeMask Framebuffer::getDrawBufferTypeMask() const ComponentTypeMask Framebuffer::getDrawBufferTypeMask() const
{ {
return mState.mDrawBufferTypeMask; return mState.mDrawBufferTypeMask;
} }
......
...@@ -115,7 +115,7 @@ class FramebufferState final : angle::NonCopyable ...@@ -115,7 +115,7 @@ class FramebufferState final : angle::NonCopyable
std::vector<GLenum> mDrawBufferStates; std::vector<GLenum> mDrawBufferStates;
GLenum mReadBufferState; GLenum mReadBufferState;
DrawBufferMask mEnabledDrawBuffers; DrawBufferMask mEnabledDrawBuffers;
DrawBufferTypeMask mDrawBufferTypeMask; ComponentTypeMask mDrawBufferTypeMask;
GLint mDefaultWidth; GLint mDefaultWidth;
GLint mDefaultHeight; GLint mDefaultHeight;
...@@ -201,7 +201,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver ...@@ -201,7 +201,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
void setDrawBuffers(size_t count, const GLenum *buffers); void setDrawBuffers(size_t count, const GLenum *buffers);
const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const; const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const;
GLenum getDrawbufferWriteType(size_t drawBuffer) const; GLenum getDrawbufferWriteType(size_t drawBuffer) const;
DrawBufferTypeMask getDrawBufferTypeMask() const; ComponentTypeMask getDrawBufferTypeMask() const;
DrawBufferMask getDrawBufferMask() const; DrawBufferMask getDrawBufferMask() const;
bool hasEnabledDrawBuffer() const; bool hasEnabledDrawBuffer() const;
......
...@@ -232,6 +232,11 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -232,6 +232,11 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
state->mNumViews = stream.readInt<int>(); state->mNumViews = stream.readInt<int>();
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
state->mAttributesTypeMask.from_ulong(stream.readInt<uint32_t>());
state->mAttributesMask = stream.readInt<uint32_t>();
static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8, static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
"Too many vertex attribs for mask"); "Too many vertex attribs for mask");
state->mActiveAttribLocationsMask = stream.readInt<unsigned long>(); state->mActiveAttribLocationsMask = stream.readInt<unsigned long>();
...@@ -372,12 +377,10 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -372,12 +377,10 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
state->mOutputVariableTypes.push_back(stream.readInt<GLenum>()); state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
} }
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFER_TYPE_MASK == 8 * sizeof(uint16_t), static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
"All bits of DrawBufferTypeMask can be contained in an uint16_t"); "All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
state->mDrawBufferTypeMask.from_ulong(stream.readInt<uint16_t>()); "into 32 bits each");
state->mDrawBufferTypeMask.from_ulong(stream.readInt<uint32_t>());
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
"All bits of DrawBufferMask can be contained in an uint32_t");
state->mActiveOutputVariables = stream.readInt<uint32_t>(); state->mActiveOutputVariables = stream.readInt<uint32_t>();
unsigned int samplerRangeLow = stream.readInt<unsigned int>(); unsigned int samplerRangeLow = stream.readInt<unsigned int>();
...@@ -450,6 +453,11 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -450,6 +453,11 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(state.mNumViews); stream.writeInt(state.mNumViews);
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
stream.writeInt(static_cast<int>(state.mAttributesTypeMask.to_ulong()));
stream.writeInt(static_cast<int>(state.mAttributesMask.to_ulong()));
stream.writeInt(state.getActiveAttribLocationsMask().to_ulong()); stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
stream.writeInt(state.getAttributes().size()); stream.writeInt(state.getAttributes().size());
...@@ -546,13 +554,11 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -546,13 +554,11 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(outputVariableType); stream.writeInt(outputVariableType);
} }
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFER_TYPE_MASK == 8 * sizeof(uint16_t), static_assert(
"All bits of DrawBufferTypeMask can be contained in an uint16_t"); IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
stream.writeInt(static_cast<uint32_t>(state.mDrawBufferTypeMask.to_ulong())); "All bits of mDrawBufferTypeMask and mActiveOutputVariables can be contained in 32 bits");
stream.writeInt(static_cast<int>(state.mDrawBufferTypeMask.to_ulong()));
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t), stream.writeInt(static_cast<int>(state.mActiveOutputVariables.to_ulong()));
"All bits of DrawBufferMask can be contained in an uint32_t");
stream.writeInt(static_cast<uint32_t>(state.mActiveOutputVariables.to_ulong()));
stream.writeInt(state.getSamplerUniformRange().low()); stream.writeInt(state.getSamplerUniformRange().low());
stream.writeInt(state.getSamplerUniformRange().high()); stream.writeInt(state.getSamplerUniformRange().high());
......
...@@ -991,6 +991,8 @@ void Program::updateLinkedShaderStages() ...@@ -991,6 +991,8 @@ void Program::updateLinkedShaderStages()
void Program::unlink() void Program::unlink()
{ {
mState.mAttributes.clear(); mState.mAttributes.clear();
mState.mAttributesTypeMask.reset();
mState.mAttributesMask.reset();
mState.mActiveAttribLocationsMask.reset(); mState.mActiveAttribLocationsMask.reset();
mState.mMaxActiveAttribLocation = 0; mState.mMaxActiveAttribLocation = 0;
mState.mLinkedTransformFeedbackVaryings.clear(); mState.mLinkedTransformFeedbackVaryings.clear();
...@@ -2365,6 +2367,9 @@ bool Program::linkAttributes(const Context *context, InfoLog &infoLog) ...@@ -2365,6 +2367,9 @@ bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
} }
} }
ASSERT(mState.mAttributesTypeMask.none());
ASSERT(mState.mAttributesMask.none());
for (const sh::Attribute &attribute : mState.mAttributes) for (const sh::Attribute &attribute : mState.mAttributes)
{ {
ASSERT(attribute.location != -1); ASSERT(attribute.location != -1);
...@@ -2376,6 +2381,14 @@ bool Program::linkAttributes(const Context *context, InfoLog &infoLog) ...@@ -2376,6 +2381,14 @@ bool Program::linkAttributes(const Context *context, InfoLog &infoLog)
mState.mActiveAttribLocationsMask.set(location); mState.mActiveAttribLocationsMask.set(location);
mState.mMaxActiveAttribLocation = mState.mMaxActiveAttribLocation =
std::max(mState.mMaxActiveAttribLocation, location + 1); std::max(mState.mMaxActiveAttribLocation, location + 1);
// gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
if (!attribute.isBuiltIn())
{
mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
location);
mState.mAttributesMask.set(location);
}
} }
} }
......
...@@ -345,6 +345,9 @@ class ProgramState final : angle::NonCopyable ...@@ -345,6 +345,9 @@ class ProgramState final : angle::NonCopyable
std::vector<sh::Attribute> mAttributes; std::vector<sh::Attribute> mAttributes;
angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask; angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
unsigned int mMaxActiveAttribLocation; unsigned int mMaxActiveAttribLocation;
ComponentTypeMask mAttributesTypeMask;
// mAttributesMask is identical to mActiveAttribLocationsMask with built-in attributes removed.
AttributesMask mAttributesMask;
// Uniforms are sorted in order: // Uniforms are sorted in order:
// 1. Non-opaque uniforms // 1. Non-opaque uniforms
...@@ -382,7 +385,7 @@ class ProgramState final : angle::NonCopyable ...@@ -382,7 +385,7 @@ class ProgramState final : angle::NonCopyable
// Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location.
std::vector<GLenum> mOutputVariableTypes; std::vector<GLenum> mOutputVariableTypes;
DrawBufferTypeMask mDrawBufferTypeMask; ComponentTypeMask mDrawBufferTypeMask;
bool mBinaryRetrieveableHint; bool mBinaryRetrieveableHint;
bool mSeparable; bool mSeparable;
...@@ -643,7 +646,9 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -643,7 +646,9 @@ class Program final : angle::NonCopyable, public LabeledObject
int getNumViews() const { return mState.getNumViews(); } int getNumViews() const { return mState.getNumViews(); }
bool usesMultiview() const { return mState.usesMultiview(); } bool usesMultiview() const { return mState.usesMultiview(); }
DrawBufferTypeMask getDrawBufferTypeMask() const { return mState.mDrawBufferTypeMask; } ComponentTypeMask getDrawBufferTypeMask() const { return mState.mDrawBufferTypeMask; }
ComponentTypeMask getAttributesTypeMask() const { return mState.mAttributesTypeMask; }
AttributesMask getAttributesMask() const { return mState.mAttributesMask; }
private: private:
~Program() override; ~Program() override;
......
...@@ -142,6 +142,12 @@ void State::initialize(const Context *context, ...@@ -142,6 +142,12 @@ void State::initialize(const Context *context,
mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); mVertexAttribCurrentValues.resize(caps.maxVertexAttributes);
// Set all indexes in state attributes type mask to float (default)
for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
mCurrentValuesTypeMask.setIndex(GL_FLOAT, i);
}
mUniformBuffers.resize(caps.maxUniformBufferBindings); mUniformBuffers.resize(caps.maxUniformBufferBindings);
mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits);
...@@ -1371,6 +1377,7 @@ void State::setVertexAttribf(GLuint index, const GLfloat values[4]) ...@@ -1371,6 +1377,7 @@ void State::setVertexAttribf(GLuint index, const GLfloat values[4])
mVertexAttribCurrentValues[index].setFloatValues(values); mVertexAttribCurrentValues[index].setFloatValues(values);
mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES);
mDirtyCurrentValues.set(index); mDirtyCurrentValues.set(index);
mCurrentValuesTypeMask.setIndex(GL_FLOAT, index);
} }
void State::setVertexAttribu(GLuint index, const GLuint values[4]) void State::setVertexAttribu(GLuint index, const GLuint values[4])
...@@ -1379,6 +1386,7 @@ void State::setVertexAttribu(GLuint index, const GLuint values[4]) ...@@ -1379,6 +1386,7 @@ void State::setVertexAttribu(GLuint index, const GLuint values[4])
mVertexAttribCurrentValues[index].setUnsignedIntValues(values); mVertexAttribCurrentValues[index].setUnsignedIntValues(values);
mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES);
mDirtyCurrentValues.set(index); mDirtyCurrentValues.set(index);
mCurrentValuesTypeMask.setIndex(GL_UNSIGNED_INT, index);
} }
void State::setVertexAttribi(GLuint index, const GLint values[4]) void State::setVertexAttribi(GLuint index, const GLint values[4])
...@@ -1387,6 +1395,7 @@ void State::setVertexAttribi(GLuint index, const GLint values[4]) ...@@ -1387,6 +1395,7 @@ void State::setVertexAttribi(GLuint index, const GLint values[4])
mVertexAttribCurrentValues[index].setIntValues(values); mVertexAttribCurrentValues[index].setIntValues(values);
mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES); mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES);
mDirtyCurrentValues.set(index); mDirtyCurrentValues.set(index);
mCurrentValuesTypeMask.setIndex(GL_INT, index);
} }
void State::setVertexAttribPointer(const Context *context, void State::setVertexAttribPointer(const Context *context,
......
...@@ -460,6 +460,7 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable ...@@ -460,6 +460,7 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
const ImageUnit &getImageUnit(GLuint unit) const; const ImageUnit &getImageUnit(GLuint unit) const;
const std::vector<Texture *> &getCompleteTextureCache() const { return mCompleteTextureCache; } const std::vector<Texture *> &getCompleteTextureCache() const { return mCompleteTextureCache; }
ComponentTypeMask getCurrentValuesTypeMask() const { return mCurrentValuesTypeMask; }
// Handle a dirty texture event. // Handle a dirty texture event.
void signal(size_t textureIndex, InitState initState) override; void signal(size_t textureIndex, InitState initState) override;
...@@ -515,6 +516,7 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable ...@@ -515,6 +516,7 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
typedef std::vector<VertexAttribCurrentValueData> VertexAttribVector; typedef std::vector<VertexAttribCurrentValueData> VertexAttribVector;
VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib
VertexArray *mVertexArray; VertexArray *mVertexArray;
ComponentTypeMask mCurrentValuesTypeMask;
// Texture and sampler bindings // Texture and sampler bindings
size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0 size_t mActiveSampler; // Active texture unit selector - GL_TEXTURE0
......
...@@ -175,6 +175,8 @@ void VertexArray::setVertexAttribFormatImpl(size_t attribIndex, ...@@ -175,6 +175,8 @@ void VertexArray::setVertexAttribFormatImpl(size_t attribIndex,
attrib->normalized = normalized; attrib->normalized = normalized;
attrib->pureInteger = pureInteger; attrib->pureInteger = pureInteger;
attrib->relativeOffset = relativeOffset; attrib->relativeOffset = relativeOffset;
mState.mVertexAttributesTypeMask.setIndex(GetVertexAttributeBaseType(*attrib), attribIndex);
mState.mEnabledAttributesMask.set(attribIndex);
} }
void VertexArray::setVertexAttribFormat(size_t attribIndex, void VertexArray::setVertexAttribFormat(size_t attribIndex,
...@@ -202,6 +204,8 @@ void VertexArray::enableAttribute(size_t attribIndex, bool enabledState) ...@@ -202,6 +204,8 @@ void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
ASSERT(attribIndex < getMaxAttribs()); ASSERT(attribIndex < getMaxAttribs());
mState.mVertexAttributes[attribIndex].enabled = enabledState; mState.mVertexAttributes[attribIndex].enabled = enabledState;
mState.mVertexAttributesTypeMask.setIndex(
GetVertexAttributeBaseType(mState.mVertexAttributes[attribIndex]), attribIndex);
mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex); mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex);
......
...@@ -69,6 +69,7 @@ class VertexArrayState final : angle::NonCopyable ...@@ -69,6 +69,7 @@ class VertexArrayState final : angle::NonCopyable
BindingPointer<Buffer> mElementArrayBuffer; BindingPointer<Buffer> mElementArrayBuffer;
std::vector<VertexBinding> mVertexBindings; std::vector<VertexBinding> mVertexBindings;
AttributesMask mEnabledAttributesMask; AttributesMask mEnabledAttributesMask;
ComponentTypeMask mVertexAttributesTypeMask;
}; };
class VertexArray final : public LabeledObject class VertexArray final : public LabeledObject
...@@ -192,6 +193,9 @@ class VertexArray final : public LabeledObject ...@@ -192,6 +193,9 @@ class VertexArray final : public LabeledObject
void syncState(const Context *context); void syncState(const Context *context);
bool hasAnyDirtyBit() const { return mDirtyBits.any(); } bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
ComponentTypeMask getAttributesTypeMask() const { return mState.mVertexAttributesTypeMask; }
AttributesMask getAttributesMask() const { return mState.mEnabledAttributesMask; }
private: private:
~VertexArray() override; ~VertexArray() override;
......
...@@ -257,50 +257,45 @@ bool operator!=(const Extents &lhs, const Extents &rhs) ...@@ -257,50 +257,45 @@ bool operator!=(const Extents &lhs, const Extents &rhs)
return !(lhs == rhs); return !(lhs == rhs);
} }
DrawBufferTypeMask::DrawBufferTypeMask() ComponentTypeMask::ComponentTypeMask()
{ {
mTypeMask.reset(); mTypeMask.reset();
} }
DrawBufferTypeMask::DrawBufferTypeMask(const DrawBufferTypeMask &other) = default; ComponentTypeMask::ComponentTypeMask(const ComponentTypeMask &other) = default;
DrawBufferTypeMask::~DrawBufferTypeMask() = default; ComponentTypeMask::~ComponentTypeMask() = default;
void DrawBufferTypeMask::reset() void ComponentTypeMask::reset()
{ {
mTypeMask.reset(); mTypeMask.reset();
} }
bool DrawBufferTypeMask::none() bool ComponentTypeMask::none()
{ {
if (mTypeMask.none()) return mTypeMask.none();
{
return true;
}
return false;
} }
void DrawBufferTypeMask::setIndex(GLenum type, size_t index) void ComponentTypeMask::setIndex(GLenum type, size_t index)
{ {
ASSERT(index <= IMPLEMENTATION_MAX_DRAW_BUFFERS); ASSERT(index <= MAX_COMPONENT_TYPE_MASK_INDEX);
mTypeMask &= ~(0x101 << index); mTypeMask &= ~(0x10001 << index);
uint16_t m = 0; uint32_t m = 0;
switch (type) switch (type)
{ {
case GL_INT: case GL_INT:
m = 0x001; m = 0x00001;
break; break;
case GL_UNSIGNED_INT: case GL_UNSIGNED_INT:
m = 0x100; m = 0x10000;
break; break;
case GL_FLOAT: case GL_FLOAT:
m = 0x101; m = 0x10001;
break; break;
case GL_NONE: case GL_NONE:
m = 0x000; m = 0x00000;
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -309,45 +304,42 @@ void DrawBufferTypeMask::setIndex(GLenum type, size_t index) ...@@ -309,45 +304,42 @@ void DrawBufferTypeMask::setIndex(GLenum type, size_t index)
mTypeMask |= m << index; mTypeMask |= m << index;
} }
unsigned long DrawBufferTypeMask::to_ulong() const unsigned long ComponentTypeMask::to_ulong() const
{ {
return mTypeMask.to_ulong(); return mTypeMask.to_ulong();
} }
void DrawBufferTypeMask::from_ulong(unsigned long mask) void ComponentTypeMask::from_ulong(unsigned long mask)
{ {
mTypeMask = mask; mTypeMask = mask;
} }
bool DrawBufferTypeMask::ProgramOutputsMatchFramebuffer(DrawBufferTypeMask outputTypes, bool ComponentTypeMask::Validate(unsigned long outputTypes,
DrawBufferTypeMask inputTypes, unsigned long inputTypes,
DrawBufferMask outputMask, unsigned long outputMask,
DrawBufferMask inputMask) unsigned long inputMask)
{ {
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFER_TYPE_MASK == 16, static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS <= MAX_COMPONENT_TYPE_MASK_INDEX,
"Draw buffer type masks should fit into 16 bits. 2 bits per draw buffer."); "Output/input masks should fit into 16 bits - 1 bit per draw buffer. The "
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS == 8, "corresponding type masks should fit into 32 bits - 2 bits per draw buffer.");
"Output/Input masks should fit into 8 bits. 1 bit per draw buffer"); static_assert(MAX_VERTEX_ATTRIBS <= MAX_COMPONENT_TYPE_MASK_INDEX,
"Output/input masks should fit into 16 bits - 1 bit per attrib. The "
// For performance reasons, draw buffer type validation is done using bit masks. We store two "corresponding type masks should fit into 32 bits - 2 bits per attrib.");
// bits representing the type split, with the low bit in the lower 8 bits of the variable,
// and the high bit in the upper 8 bits of the variable. This is done so we can AND with the // For performance reasons, draw buffer and attribute type validation is done using bit masks.
// elswewhere used DrawBufferMask. // We store two bits representing the type split, with the low bit in the lower 16 bits of the
const unsigned long outputTypeBits = outputTypes.to_ulong(); // variable, and the high bit in the upper 16 bits of the variable. This is done so we can AND
const unsigned long inputTypeBits = inputTypes.to_ulong(); // with the elswewhere used DrawBufferMask or AttributeMask.
unsigned long outputMaskBits = outputMask.to_ulong(); // OR the masks with themselves, shifted 16 bits. This is to match our split type bits.
unsigned long inputMaskBits = inputMask.to_ulong(); outputMask |= (outputMask << MAX_COMPONENT_TYPE_MASK_INDEX);
inputMask |= (inputMask << MAX_COMPONENT_TYPE_MASK_INDEX);
// OR the masks with themselves, shifted 8 bits. This is to match our split type bits.
outputMaskBits |= (outputMaskBits << 8);
inputMaskBits |= (inputMaskBits << 8);
// To validate: // To validate:
// 1. Remove any indexes that are not enabled in the framebuffer (& inputMask) // 1. Remove any indexes that are not enabled in the input (& inputMask)
// 2. Remove any indexes that exist in program, but not in framebuffer (& outputMask) // 2. Remove any indexes that exist in output, but not in input (& outputMask)
// 3. Use XOR to check for a match // 3. Use == to verify equality
return (outputTypeBits & inputMaskBits) == ((inputTypeBits & outputMaskBits) & inputMaskBits); return (outputTypes & inputMask) == ((inputTypes & outputMask) & inputMask);
} }
} // namespace gl } // namespace gl
...@@ -290,24 +290,26 @@ using UniformBlockBindingMask = angle::BitSet<IMPLEMENTATION_MAX_COMBINED_SHADER ...@@ -290,24 +290,26 @@ using UniformBlockBindingMask = angle::BitSet<IMPLEMENTATION_MAX_COMBINED_SHADER
// Used in Framebuffer / Program // Used in Framebuffer / Program
using DrawBufferMask = angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFERS>; using DrawBufferMask = angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFERS>;
constexpr int IMPLEMENTATION_MAX_DRAW_BUFFER_TYPE_MASK = 16;
struct DrawBufferTypeMask final constexpr size_t MAX_COMPONENT_TYPE_MASK_INDEX = 16;
struct ComponentTypeMask final
{ {
DrawBufferTypeMask(); ComponentTypeMask();
DrawBufferTypeMask(const DrawBufferTypeMask &other); ComponentTypeMask(const ComponentTypeMask &other);
~DrawBufferTypeMask(); ~ComponentTypeMask();
void reset(); void reset();
bool none(); bool none();
void setIndex(GLenum type, size_t index); void setIndex(GLenum type, size_t index);
unsigned long to_ulong() const; unsigned long to_ulong() const;
void from_ulong(unsigned long mask); void from_ulong(unsigned long mask);
static bool ProgramOutputsMatchFramebuffer(DrawBufferTypeMask outputTypes, static bool Validate(unsigned long outputTypes,
DrawBufferTypeMask inputTypes, unsigned long inputTypes,
DrawBufferMask outputMask, unsigned long outputMask,
DrawBufferMask inputMask); unsigned long inputMask);
private: private:
angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFER_TYPE_MASK> mTypeMask; // Each index type is represented by 2 bits
angle::BitSet<MAX_COMPONENT_TYPE_MASK_INDEX * 2> mTypeMask;
}; };
using ContextID = uintptr_t; using ContextID = uintptr_t;
......
...@@ -396,9 +396,10 @@ bool ValidateFragmentShaderColorBufferTypeMatch(ValidationContext *context) ...@@ -396,9 +396,10 @@ bool ValidateFragmentShaderColorBufferTypeMatch(ValidationContext *context)
const Program *program = context->getGLState().getProgram(); const Program *program = context->getGLState().getProgram();
const Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer(); const Framebuffer *framebuffer = context->getGLState().getDrawFramebuffer();
if (!DrawBufferTypeMask::ProgramOutputsMatchFramebuffer( if (!ComponentTypeMask::Validate(program->getDrawBufferTypeMask().to_ulong(),
program->getDrawBufferTypeMask(), framebuffer->getDrawBufferTypeMask(), framebuffer->getDrawBufferTypeMask().to_ulong(),
program->getActiveOutputVariables(), framebuffer->getDrawBufferMask())) program->getActiveOutputVariables().to_ulong(),
framebuffer->getDrawBufferMask().to_ulong()))
{ {
ANGLE_VALIDATION_ERR(context, InvalidOperation(), DrawBufferTypeMismatch); ANGLE_VALIDATION_ERR(context, InvalidOperation(), DrawBufferTypeMismatch);
return false; return false;
...@@ -412,32 +413,21 @@ bool ValidateVertexShaderAttributeTypeMatch(ValidationContext *context) ...@@ -412,32 +413,21 @@ bool ValidateVertexShaderAttributeTypeMatch(ValidationContext *context)
const auto &glState = context->getGLState(); const auto &glState = context->getGLState();
const Program *program = context->getGLState().getProgram(); const Program *program = context->getGLState().getProgram();
const VertexArray *vao = context->getGLState().getVertexArray(); const VertexArray *vao = context->getGLState().getVertexArray();
const auto &vertexAttribs = vao->getVertexAttributes();
const auto &currentValues = glState.getVertexAttribCurrentValues();
for (const sh::Attribute &shaderAttribute : program->getAttributes()) unsigned long stateCurrentValuesTypeBits = glState.getCurrentValuesTypeMask().to_ulong();
{ unsigned long vaoAttribTypeBits = vao->getAttributesTypeMask().to_ulong();
// gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute. unsigned long vaoAttribEnabledMask = vao->getAttributesMask().to_ulong();
if (shaderAttribute.isBuiltIn())
{
continue;
}
GLenum shaderInputType = VariableComponentType(shaderAttribute.type);
const auto &attrib = vertexAttribs[shaderAttribute.location]; vaoAttribEnabledMask |= vaoAttribEnabledMask << MAX_COMPONENT_TYPE_MASK_INDEX;
GLenum vertexType = attrib.enabled ? GetVertexAttributeBaseType(attrib) vaoAttribTypeBits = (vaoAttribEnabledMask & vaoAttribTypeBits);
: currentValues[shaderAttribute.location].Type; vaoAttribTypeBits |= (~vaoAttribEnabledMask & stateCurrentValuesTypeBits);
if (shaderInputType != GL_NONE && vertexType != GL_NONE && shaderInputType != vertexType) if (!ComponentTypeMask::Validate(program->getAttributesTypeMask().to_ulong(), vaoAttribTypeBits,
{ program->getAttributesMask().to_ulong(), 0xFFFF))
context->handleError(InvalidOperation() << "Vertex shader input type does not " {
"match the type of the bound vertex " ANGLE_VALIDATION_ERR(context, InvalidOperation(), VertexShaderTypeMismatch);
"attribute."); return false;
return false;
}
} }
return true; return true;
} }
......
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