Commit 471b8d4c by James Darpinian Committed by Commit Bot

WebGL, D3D: Forbid multiple TF outputs in one buffer

Implementing a WebGL spec change: https://github.com/KhronosGroup/WebGL/pull/2658 Fixes WebGL 2 conformance test: conformance2/transform_feedback/same-buffer-two-binding-points.html Also applying the change to D3D backends because they can't support multiple transform feedback outputs in one buffer. Bug: chromium:866089 Change-Id: I8d7eda14225c13efb7ca1ed974239332be4e79a6 Reviewed-on: https://chromium-review.googlesource.com/c/1347749 Commit-Queue: James Darpinian <jdarpinian@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 5552cdf0
...@@ -268,6 +268,11 @@ bool Buffer::isBoundForTransformFeedbackAndOtherUse() const ...@@ -268,6 +268,11 @@ bool Buffer::isBoundForTransformFeedbackAndOtherUse() const
mState.mBindingCount - mState.mTransformFeedbackGenericBindingCount; mState.mBindingCount - mState.mTransformFeedbackGenericBindingCount;
} }
bool Buffer::isDoubleBoundForTransformFeedback() const
{
return mState.mTransformFeedbackIndexedBindingCount > 1;
}
void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed) void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed)
{ {
ASSERT(bound || mState.mBindingCount > 0); ASSERT(bound || mState.mBindingCount > 0);
......
...@@ -123,6 +123,7 @@ class Buffer final : public RefCountObject, ...@@ -123,6 +123,7 @@ class Buffer final : public RefCountObject,
bool isBound() const; bool isBound() const;
bool isBoundForTransformFeedbackAndOtherUse() const; bool isBoundForTransformFeedbackAndOtherUse() const;
bool isDoubleBoundForTransformFeedback() const;
void onTFBindingChanged(const Context *context, bool bound, bool indexed); void onTFBindingChanged(const Context *context, bool bound, bool indexed);
void onNonTFBindingChanged(int incr) { mState.mBindingCount += incr; } void onNonTFBindingChanged(int incr) { mState.mBindingCount += incr; }
......
...@@ -286,7 +286,8 @@ Limitations::Limitations() ...@@ -286,7 +286,8 @@ Limitations::Limitations()
noSeparateStencilRefsAndMasks(false), noSeparateStencilRefsAndMasks(false),
shadersRequireIndexedLoopValidation(false), shadersRequireIndexedLoopValidation(false),
noSimultaneousConstantColorAndAlphaBlendFunc(false), noSimultaneousConstantColorAndAlphaBlendFunc(false),
noFlexibleVaryingPacking(false) noFlexibleVaryingPacking(false),
noDoubleBoundTransformFeedbackBuffers(false)
{ {
} }
......
...@@ -506,6 +506,9 @@ struct Limitations ...@@ -506,6 +506,9 @@ struct Limitations
// D3D9 does not support flexible varying register packing. // D3D9 does not support flexible varying register packing.
bool noFlexibleVaryingPacking; bool noFlexibleVaryingPacking;
// D3D does not support having multiple transform feedback outputs go to the same buffer.
bool noDoubleBoundTransformFeedbackBuffers;
}; };
struct TypePrecision struct TypePrecision
......
...@@ -104,6 +104,8 @@ constexpr const char *kErrorDestinationTextureTooSmall = "Destination texture to ...@@ -104,6 +104,8 @@ constexpr const char *kErrorDestinationTextureTooSmall = "Destination texture to
constexpr const char *kErrorDimensionsMustBePow2 = "Texture dimensions must be power-of-two."; constexpr const char *kErrorDimensionsMustBePow2 = "Texture dimensions must be power-of-two.";
constexpr const char *kErrorDispatchIndirectBufferNotBound = constexpr const char *kErrorDispatchIndirectBufferNotBound =
"Dispatch indirect buffer must be bound."; "Dispatch indirect buffer must be bound.";
constexpr const char *kErrorDoubleBoundTransformFeedbackBuffer =
"Transform feedback has a buffer bound to multiple outputs.";
constexpr const char *kErrorDrawIndirectBufferNotBound = "Draw indirect buffer must be bound."; constexpr const char *kErrorDrawIndirectBufferNotBound = "Draw indirect buffer must be bound.";
constexpr const char *kErrorDrawBufferTypeMismatch = constexpr const char *kErrorDrawBufferTypeMismatch =
"Fragment shader output type does not match the bound framebuffer attachment type."; "Fragment shader output type does not match the bound framebuffer attachment type.";
......
...@@ -1654,6 +1654,9 @@ void GenerateCaps(ID3D11Device *device, ...@@ -1654,6 +1654,9 @@ void GenerateCaps(ID3D11Device *device,
// D3D11 cannot support constant color and alpha blend funcs together // D3D11 cannot support constant color and alpha blend funcs together
limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
// D3D11 does not support multiple transform feedback outputs writing to the same buffer.
limitations->noDoubleBoundTransformFeedbackBuffers = true;
#ifdef ANGLE_ENABLE_WINDOWS_STORE #ifdef ANGLE_ENABLE_WINDOWS_STORE
// Setting a non-zero divisor on attribute zero doesn't work on certain Windows Phone 8-era // Setting a non-zero divisor on attribute zero doesn't work on certain Windows Phone 8-era
// devices. We should prevent developers from doing this on ALL Windows Store devices. This will // devices. We should prevent developers from doing this on ALL Windows Store devices. This will
......
...@@ -2472,11 +2472,22 @@ bool ValidateBeginTransformFeedback(Context *context, PrimitiveMode primitiveMod ...@@ -2472,11 +2472,22 @@ bool ValidateBeginTransformFeedback(Context *context, PrimitiveMode primitiveMod
for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++) for (size_t i = 0; i < transformFeedback->getIndexedBufferCount(); i++)
{ {
const auto &buffer = transformFeedback->getIndexedBuffer(i); const auto &buffer = transformFeedback->getIndexedBuffer(i);
if (buffer.get() && buffer->isMapped()) if (buffer.get())
{ {
context->validationError(GL_INVALID_OPERATION, if (buffer->isMapped())
"Transform feedback has a mapped buffer."); {
return false; context->validationError(GL_INVALID_OPERATION,
"Transform feedback has a mapped buffer.");
return false;
}
if ((context->getLimitations().noDoubleBoundTransformFeedbackBuffers ||
context->getExtensions().webglCompatibility) &&
buffer->isDoubleBoundForTransformFeedback())
{
context->validationError(GL_INVALID_OPERATION,
kErrorDoubleBoundTransformFeedbackBuffer);
return false;
}
} }
} }
......
...@@ -4254,6 +4254,30 @@ TEST_P(WebGL2CompatibilityTest, TransformFeedbackCheckNullDeref) ...@@ -4254,6 +4254,30 @@ TEST_P(WebGL2CompatibilityTest, TransformFeedbackCheckNullDeref)
EXPECT_GL_ERROR(GL_INVALID_OPERATION); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
} }
// We should forbid two transform feedback outputs going to the same buffer.
TEST_P(WebGL2CompatibilityTest, TransformFeedbackDoubleBinding)
{
constexpr char kVS[] =
R"(attribute float a; varying float b; varying float c; void main() { b = a; c = a; })";
constexpr char kFS[] = R"(void main(){})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
static const char *varyings[] = {"b", "c"};
glTransformFeedbackVaryings(program, 2, varyings, GL_SEPARATE_ATTRIBS);
glLinkProgram(program);
glUseProgram(program);
ASSERT_GL_NO_ERROR();
// Bind the transform feedback varyings to non-overlapping regions of the same buffer.
GLBuffer buffer;
glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer, 0, 4);
glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 1, buffer, 4, 4);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 8, nullptr, GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
// Two varyings bound to the same buffer should be an error.
glBeginTransformFeedback(GL_POINTS);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Check the return type of a given parameter upon getting the active uniforms. // Check the return type of a given parameter upon getting the active uniforms.
TEST_P(WebGL2CompatibilityTest, UniformVariablesReturnTypes) TEST_P(WebGL2CompatibilityTest, UniformVariablesReturnTypes)
{ {
......
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