Commit 282fb409 by Shahbaz Youssefi Committed by Commit Bot

Fix link validation of I/O block members

Location and struct name matching for fields was missing as they only apply to I/O blocks and not varyings of struct type. Bug: angleproject:3580 Change-Id: I69083f39088458da72828b418be3068187a30fcc Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2587456Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent da8c2261
......@@ -486,6 +486,11 @@ const char *GetLinkMismatchErrorString(LinkMismatchError linkError)
return "Layout qualifier";
case LinkMismatchError::MATRIX_PACKING_MISMATCH:
return "Matrix Packing";
case LinkMismatchError::FIELD_LOCATION_MISMATCH:
return "Field location";
case LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH:
return "Field structure name";
default:
UNREACHABLE();
return "";
......@@ -3656,8 +3661,21 @@ bool Program::doShaderVariablesMatch(int outputShaderVersion,
bool namesMatch = input.isSameNameAtLinkTime(output);
bool locationsMatch = input.location != -1 && input.location == output.location;
// An output block is considered to match an input block in the subsequent
// shader if the two blocks have the same block name, and the members of the
// block match exactly in name, type, qualification, and declaration order.
//
// - For the purposes of shader interface matching, the gl_PointSize
// member of the intrinsically declared gl_PerVertex shader interface
// block is ignored.
// - Output blocks that do not match in name, but have a location and match
// in every other way listed above may be considered to match by some
// implementations, but not all - so this behaviour should not be relied
// upon.
// An output variable is considered to match an input variable in the subsequent
// shader if:
//
// - the two variables match in name, type, and qualification; or
// - the two variables are declared with the same location qualifier and
// match in type and qualification.
......@@ -3681,8 +3699,7 @@ bool Program::doShaderVariablesMatch(int outputShaderVersion,
return false;
}
// [OpenGL ES 3.1] Chapter 7.4.1 "Shader Interface Matching" Page 91
// TODO(jiawei.shao@intel.com): add validation on input/output blocks matching
// [OpenGL ES 3.2] Chapter 7.4.1 "Shader Interface Matching"
bool Program::linkValidateShaderInterfaceMatching(
const std::vector<sh::ShaderVariable> &outputVaryings,
const std::vector<sh::ShaderVariable> &inputVaryings,
......@@ -4235,6 +4252,19 @@ LinkMismatchError Program::LinkValidateVariablesBase(const sh::ShaderVariable &v
return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
}
if (variable1.isShaderIOBlock && variable2.isShaderIOBlock)
{
if (member1.location != member2.location)
{
return LinkMismatchError::FIELD_LOCATION_MISMATCH;
}
if (member1.structName != member2.structName)
{
return LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH;
}
}
LinkMismatchError linkErrorOnField = LinkValidateVariablesBase(
member1, member2, validatePrecision, true, mismatchedStructOrBlockMemberName);
if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
......
......@@ -85,6 +85,10 @@ enum class LinkMismatchError
// Interface block specific
LAYOUT_QUALIFIER_MISMATCH,
MATRIX_PACKING_MISMATCH,
// I/O block specific
FIELD_LOCATION_MISMATCH,
FIELD_STRUCT_NAME_MISMATCH,
};
void LogLinkMismatch(InfoLog &infoLog,
......
......@@ -189,10 +189,6 @@
3571 VULKAN : dEQP-GLES31.functional.geometry_shading.*transform_feedback* = SKIP
3571 VULKAN : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.*geo* = SKIP
// Shader I/O blocks:
// Missing matching of struct name in member fields of matching nameless I/O blocks
3580 VULKAN : dEQP-GLES31.functional.separate_shader.validation.es31.io_blocks.mismatch_different_member_struct_names = FAIL
////
//// AMD Vulkan expectations
////
......
......@@ -9009,6 +9009,362 @@ void main()
EXPECT_GL_NO_ERROR();
}
// Validate that link fails with I/O block member name mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberNameMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
out VSBlock { vec4 a; vec4 b[2]; } blockOut1;
void main()
{
blockOut1.a = vec4(0);
blockOut1.b[0] = vec4(0);
blockOut1.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
in VSBlock { vec4 c; vec4 b[2]; } blockIn1;
void main()
{
color = vec4(blockIn1.c.x, blockIn1.b[0].y, blockIn1.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member array size mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberArraySizeMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
out VSBlock { vec4 a; vec4 b[2]; } blockOut1;
void main()
{
blockOut1.a = vec4(0);
blockOut1.b[0] = vec4(0);
blockOut1.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
in VSBlock { vec4 a; vec4 b[3]; } blockIn1;
void main()
{
color = vec4(blockIn1.a.x, blockIn1.b[0].y, blockIn1.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member type mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberTypeMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
out VSBlock { vec4 a; vec4 b[2]; } blockOut1;
void main()
{
blockOut1.a = vec4(0);
blockOut1.b[0] = vec4(0);
blockOut1.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
in VSBlock { vec3 a; vec4 b[2]; } blockIn1;
void main()
{
color = vec4(blockIn1.a.x, blockIn1.b[0].y, blockIn1.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block location mismatches
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkLocationMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
layout(location = 2) out VSBlock { vec4 a; vec4 b[2]; } blockOut1;
void main()
{
blockOut1.a = vec4(0);
blockOut1.b[0] = vec4(0);
blockOut1.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
layout(location = 1) in VSBlock { vec4 a; vec4 b[2]; } blockIn1;
void main()
{
color = vec4(blockIn1.a.x, blockIn1.b[0].y, blockIn1.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member location mismatches
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberLocationMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
out VSBlock { vec4 a; layout(location = 2) vec4 b[2]; } blockOut1;
void main()
{
blockOut1.a = vec4(0);
blockOut1.b[0] = vec4(0);
blockOut1.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
in VSBlock { vec4 a; layout(location = 3) vec4 b[2]; } blockIn1;
void main()
{
color = vec4(blockIn1.a.x, blockIn1.b[0].y, blockIn1.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member struct name mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberStructNameMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
struct S1 { vec4 a; vec4 b[2]; };
out VSBlock { S1 s; } blockOut1;
void main()
{
blockOut1.s.a = vec4(0);
blockOut1.s.b[0] = vec4(0);
blockOut1.s.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
struct S2 { vec4 a; vec4 b[2]; };
in VSBlock { S2 s; } blockIn1;
void main()
{
color = vec4(blockIn1.s.a.x, blockIn1.s.b[0].y, blockIn1.s.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member struct member name mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberStructMemberNameMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
struct S { vec4 c; vec4 b[2]; };
out VSBlock { S s; } blockOut1;
void main()
{
blockOut1.s.c = vec4(0);
blockOut1.s.b[0] = vec4(0);
blockOut1.s.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
struct S { vec4 a; vec4 b[2]; };
in VSBlock { S s; } blockIn1;
void main()
{
color = vec4(blockIn1.s.a.x, blockIn1.s.b[0].y, blockIn1.s.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member struct member type mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberStructMemberTypeMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
struct S { vec4 a; vec4 b[2]; };
out VSBlock { S s; } blockOut1;
void main()
{
blockOut1.s.a = vec4(0);
blockOut1.s.b[0] = vec4(0);
blockOut1.s.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
struct S { vec3 a; vec4 b[2]; };
in VSBlock { S s; } blockIn1;
void main()
{
color = vec4(blockIn1.s.a.x, blockIn1.s.b[0].y, blockIn1.s.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member struct member array size mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberStructMemberArraySizeMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
struct S { vec4 a; vec4 b[3]; };
out VSBlock { S s; } blockOut1;
void main()
{
blockOut1.s.a = vec4(0);
blockOut1.s.b[0] = vec4(0);
blockOut1.s.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
struct S { vec4 a; vec4 b[2]; };
in VSBlock { S s; } blockIn1;
void main()
{
color = vec4(blockIn1.s.a.x, blockIn1.s.b[0].y, blockIn1.s.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member struct member count mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberStructMemberCountMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
struct S { vec4 a; vec4 b[2]; vec4 c; };
out VSBlock { S s; } blockOut1;
void main()
{
blockOut1.s.c = vec4(0);
blockOut1.s.b[0] = vec4(0);
blockOut1.s.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
struct S { vec4 a; vec4 b[2]; };
in VSBlock { S s; } blockIn1;
void main()
{
color = vec4(blockIn1.s.a.x, blockIn1.s.b[0].y, blockIn1.s.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
// Validate that link fails with I/O block member nested struct mismatches.
TEST_P(GLSLTest_ES31, NegativeIOBlocksLinkMemberNestedStructMismatch)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_io_blocks"));
constexpr char kVS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
in highp vec4 position;
struct S1 { vec4 c; vec4 b[2]; };
struct S2 { S1 s; };
struct S3 { S2 s; };
out VSBlock { S3 s; } blockOut1;
void main()
{
blockOut1.s.s.s.c = vec4(0);
blockOut1.s.s.s.b[0] = vec4(0);
blockOut1.s.s.s.b[1] = vec4(0);
gl_Position = position;
})";
constexpr char kFS[] = R"(#version 310 es
#extension GL_EXT_shader_io_blocks : require
precision mediump float;
layout(location = 0) out mediump vec4 color;
struct S1 { vec4 a; vec4 b[2]; };
struct S2 { S1 s; };
struct S3 { S2 s; };
in VSBlock { S3 s; } blockIn1;
void main()
{
color = vec4(blockIn1.s.s.s.a.x, blockIn1.s.s.s.b[0].y, blockIn1.s.s.s.b[1].z, 1.0);
})";
GLuint program = CompileProgram(kVS, kFS);
EXPECT_EQ(0u, program);
}
} // anonymous namespace
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
......
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