Commit 881b7bfa by Jiawei Shao Committed by Commit Bot

ES31: Refactor link mismatch error log

This patch intends to refactor the structure of logging link mismatch errors to meet the new GLES 3.1 program link requirements and support linking program with geometry shader. This patch is mainly focusing on the following 4 issues: 1. There are totally 14 places that log the link mismatch errors in almost same format. 2. A temporary string is created (STRUCT_NAME.FIELD_NAME) before checking a field of a block, which is of no use if link succeeds. 3. LinkValidateVariablesBase needs to know "shaderTypes" if we support geometry shader based on current structure. Since uniforms are checked in the range of the whole program, it is unnecessary to know in which shader a uniform is defined if link succeeds. 4. GLES 3.1 regards varyings with same location but different names as matched, so it isn't enough to log errors only by one name. This patch can solve all these issues by the following 3 changes: 1. Replace "infoLog" and "variableNames" by "mismatchedFieldName" (the complete field name if the mismatch occurs on a field of a struct or block). 2. Use enum LinkMismatchError as the return value of all linkValidate* functions to reflect the detail of the link mismatch error. 3. Log all the link mismatch errors by InfoLog::logLinkMismatch where we can get shader types instead of passing them into linkValidate* functions. BUG=angleproject:1941, angleproject:2144 TEST=angle_end2end_tests Change-Id: I3ed876d61f812cc7a45a6a3c5fec0b4a88b9cc2c Reviewed-on: https://chromium-review.googlesource.com/844215 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent c13bda86
......@@ -52,6 +52,31 @@ class Framebuffer;
extern const char * const g_fakepath;
enum class LinkMismatchError
{
// Shared
NO_MISMATCH,
TYPE_MISMATCH,
ARRAY_SIZE_MISMATCH,
PRECISION_MISMATCH,
STRUCT_NAME_MISMATCH,
FIELD_NUMBER_MISMATCH,
FIELD_NAME_MISMATCH,
// Varying specific
INTERPOLATION_TYPE_MISMATCH,
INVARIANCE_MISMATCH,
// Uniform specific
BINDING_MISMATCH,
LOCATION_MISMATCH,
OFFSET_MISMATCH,
// Interface block specific
LAYOUT_QUALIFIER_MISMATCH,
MATRIX_PACKING_MISMATCH
};
class InfoLog : angle::NonCopyable
{
public:
......@@ -133,6 +158,14 @@ class InfoLog : angle::NonCopyable
std::unique_ptr<std::stringstream> mLazyStream;
};
void LogLinkMismatch(InfoLog &infoLog,
const std::string &variableName,
const char *variableType,
LinkMismatchError linkError,
const std::string &mismatchedStructOrBlockFieldName,
GLenum shaderType1,
GLenum shaderType2);
// Struct used for correlating uniforms/elements of uniform arrays to handles
struct VariableLocation
{
......@@ -586,11 +619,11 @@ class Program final : angle::NonCopyable, public LabeledObject
GLuint getTransformFeedbackVaryingResourceIndex(const GLchar *name) const;
const TransformFeedbackVarying &getTransformFeedbackVaryingResource(GLuint index) const;
static bool LinkValidateInterfaceBlockFields(InfoLog &infoLog,
const std::string &uniformName,
const sh::InterfaceBlockField &vertexUniform,
const sh::InterfaceBlockField &fragmentUniform,
bool webglCompatibility);
static LinkMismatchError LinkValidateInterfaceBlockFields(
const sh::InterfaceBlockField &blockField1,
const sh::InterfaceBlockField &blockField2,
bool webglCompatibility,
std::string *mismatchedBlockFieldName);
void addRef();
void release(const Context *context);
......@@ -621,11 +654,11 @@ class Program final : angle::NonCopyable, public LabeledObject
const ProgramState &getState() const { return mState; }
static bool LinkValidateVariablesBase(InfoLog &infoLog,
const std::string &variableName,
const sh::ShaderVariable &vertexVariable,
const sh::ShaderVariable &fragmentVariable,
bool validatePrecision);
static LinkMismatchError LinkValidateVariablesBase(
const sh::ShaderVariable &variable1,
const sh::ShaderVariable &variable2,
bool validatePrecision,
std::string *mismatchedStructOrBlockMemberName);
GLuint getInputResourceIndex(const GLchar *name) const;
GLuint getOutputResourceIndex(const GLchar *name) const;
......@@ -673,16 +706,15 @@ class Program final : angle::NonCopyable, public LabeledObject
void updateLinkedShaderStages();
static bool AreMatchingInterfaceBlocks(InfoLog &infoLog,
const sh::InterfaceBlock &vertexInterfaceBlock,
const sh::InterfaceBlock &fragmentInterfaceBlock,
bool webglCompatibility);
static LinkMismatchError AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
const sh::InterfaceBlock &interfaceBlock2,
bool webglCompatibility,
std::string *mismatchedBlockFieldName);
static bool LinkValidateVaryings(InfoLog &infoLog,
const std::string &varyingName,
const sh::Varying &vertexVarying,
const sh::Varying &fragmentVarying,
int shaderVersion);
static LinkMismatchError LinkValidateVaryings(const sh::Varying &outputVarying,
const sh::Varying &inputVarying,
int shaderVersion,
std::string *mismatchedStructFieldName);
bool linkValidateBuiltInVaryings(const Context *context, InfoLog &infoLog) const;
bool linkValidateTransformFeedback(const gl::Context *context,
InfoLog &infoLog,
......
......@@ -4,9 +4,9 @@
// found in the LICENSE file.
//
// UniformLinker.cpp: implements link-time checks for default block uniforms, and generates uniform
// locations. Populates data structures related to uniforms so that they can be stored in program
// state.
// ProgramLinkedResources.cpp: implements link-time checks for default block uniforms, and generates
// uniform locations. Populates data structures related to uniforms so that they can be stored in
// program state.
#include "libANGLE/ProgramLinkedResources.h"
......@@ -131,10 +131,14 @@ bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &in
auto entry = linkedUniforms.find(fragmentUniform.name);
if (entry != linkedUniforms.end())
{
const sh::Uniform &linkedUniform = *(entry->second);
const std::string &uniformName = "uniform '" + linkedUniform.name + "'";
if (!LinkValidateUniforms(infoLog, uniformName, linkedUniform, fragmentUniform))
const sh::Uniform &vertexUniform = *(entry->second);
std::string mismatchedStructFieldName;
LinkMismatchError linkError =
LinkValidateUniforms(vertexUniform, fragmentUniform, &mismatchedStructFieldName);
if (linkError != LinkMismatchError::NO_MISMATCH)
{
LogLinkMismatch(infoLog, fragmentUniform.name, "uniform", linkError,
mismatchedStructFieldName, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER);
return false;
}
}
......@@ -143,10 +147,9 @@ bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &in
}
// GLSL ES Spec 3.00.3, section 4.3.5.
bool UniformLinker::LinkValidateUniforms(InfoLog &infoLog,
const std::string &uniformName,
const sh::Uniform &vertexUniform,
const sh::Uniform &fragmentUniform)
LinkMismatchError UniformLinker::LinkValidateUniforms(const sh::Uniform &uniform1,
const sh::Uniform &uniform2,
std::string *mismatchedStructFieldName)
{
#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
const bool validatePrecision = true;
......@@ -154,37 +157,31 @@ bool UniformLinker::LinkValidateUniforms(InfoLog &infoLog,
const bool validatePrecision = false;
#endif
if (!Program::LinkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform,
validatePrecision))
LinkMismatchError linkError = Program::LinkValidateVariablesBase(
uniform1, uniform2, validatePrecision, mismatchedStructFieldName);
if (linkError != LinkMismatchError::NO_MISMATCH)
{
return false;
return linkError;
}
// GLSL ES Spec 3.10.4, section 4.4.5.
if (vertexUniform.binding != -1 && fragmentUniform.binding != -1 &&
vertexUniform.binding != fragmentUniform.binding)
if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
{
infoLog << "Binding layout qualifiers for " << uniformName
<< " differ between vertex and fragment shaders.";
return false;
return LinkMismatchError::BINDING_MISMATCH;
}
// GLSL ES Spec 3.10.4, section 9.2.1.
if (vertexUniform.location != -1 && fragmentUniform.location != -1 &&
vertexUniform.location != fragmentUniform.location)
if (uniform1.location != -1 && uniform2.location != -1 &&
uniform1.location != uniform2.location)
{
infoLog << "Location layout qualifiers for " << uniformName
<< " differ between vertex and fragment shaders.";
return false;
return LinkMismatchError::LOCATION_MISMATCH;
}
if (vertexUniform.offset != fragmentUniform.offset)
if (uniform1.offset != uniform2.offset)
{
infoLog << "Offset layout qualifiers for " << uniformName
<< " differ between vertex and fragment shaders.";
return false;
return LinkMismatchError::OFFSET_MISMATCH;
}
return true;
return LinkMismatchError::NO_MISMATCH;
}
bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
......
......@@ -4,9 +4,9 @@
// found in the LICENSE file.
//
// UniformLinker.h: implements link-time checks for default block uniforms, and generates uniform
// locations. Populates data structures related to uniforms so that they can be stored in program
// state.
// ProgramLinkedResources.h: implements link-time checks for default block uniforms, and generates
// uniform locations. Populates data structures related to uniforms so that they can be stored in
// program state.
#ifndef LIBANGLE_UNIFORMLINKER_H_
#define LIBANGLE_UNIFORMLINKER_H_
......@@ -32,6 +32,7 @@ struct Caps;
class Context;
class InfoLog;
struct InterfaceBlock;
enum class LinkMismatchError;
struct LinkedUniform;
class ProgramState;
class ProgramBindings;
......@@ -80,10 +81,9 @@ class UniformLinker final : angle::NonCopyable
bool validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const;
static bool LinkValidateUniforms(InfoLog &infoLog,
const std::string &uniformName,
const sh::Uniform &vertexUniform,
const sh::Uniform &fragmentUniform);
static LinkMismatchError LinkValidateUniforms(const sh::Uniform &uniform1,
const sh::Uniform &uniform2,
std::string *mismatchedStructFieldName);
bool flattenUniformsAndCheckCapsForShader(const Context *context,
Shader *shader,
......
......@@ -74,6 +74,28 @@ bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y)
return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
}
const char *GetShaderTypeString(GLenum type)
{
switch (type)
{
case GL_VERTEX_SHADER:
return "VERTEX";
case GL_FRAGMENT_SHADER:
return "FRAGMENT";
case GL_COMPUTE_SHADER:
return "COMPUTE";
case GL_GEOMETRY_SHADER_EXT:
return "GEOMETRY";
default:
UNREACHABLE();
return "";
}
}
ShaderState::ShaderState(GLenum shaderType)
: mLabel(),
mShaderType(shaderType),
......
......@@ -207,6 +207,8 @@ class Shader final : angle::NonCopyable, public LabeledObject
};
bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y);
const char *GetShaderTypeString(GLenum type);
} // namespace gl
#endif // LIBANGLE_SHADER_H_
......@@ -16,31 +16,6 @@
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h"
// Definitions local to the translation unit
namespace
{
const char *GetShaderTypeString(GLenum type)
{
switch (type)
{
case GL_VERTEX_SHADER:
return "VERTEX";
case GL_FRAGMENT_SHADER:
return "FRAGMENT";
case GL_COMPUTE_SHADER:
return "COMPUTE";
default:
UNREACHABLE();
return "";
}
}
} // anonymous namespace
namespace rx
{
......@@ -94,7 +69,7 @@ std::string ShaderD3D::getDebugInfo() const
return "";
}
return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mData.getShaderType()) +
return mDebugInfo + std::string("\n// ") + gl::GetShaderTypeString(mData.getShaderType()) +
" SHADER END\n";
}
......@@ -241,7 +216,7 @@ bool ShaderD3D::postTranslateCompile(gl::Compiler *compiler, std::string *infoLo
}
mDebugInfo +=
std::string("// ") + GetShaderTypeString(mData.getShaderType()) + " SHADER BEGIN\n";
std::string("// ") + gl::GetShaderTypeString(mData.getShaderType()) + " SHADER BEGIN\n";
mDebugInfo += "\n// GLSL BEGIN\n\n" + mData.getSource() + "\n\n// GLSL END\n\n\n";
mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + translatedSource + "\n// INITIAL HLSL END\n\n\n";
// Successive steps will append more info
......
......@@ -449,6 +449,33 @@ class GLSLTest : public ANGLETest
return "";
}
void validateComponentsInErrorMessage(const std::string &vertexShader,
const std::string &fragmentShader,
const std::string &expectedErrorType,
const std::string &expectedVariableFullName)
{
GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
GLuint program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glDetachShader(program, vs);
glDetachShader(program, fs);
glDeleteShader(vs);
glDeleteShader(fs);
const std::string &errorMessage = QueryErrorMessage(program);
EXPECT_NE(std::string::npos, errorMessage.find(expectedErrorType));
EXPECT_NE(std::string::npos, errorMessage.find(expectedVariableFullName));
glDeleteProgram(program);
ASSERT_GL_NO_ERROR();
}
std::string mSimpleVSSource;
};
......@@ -3996,6 +4023,250 @@ TEST_P(GLSLTest, ClearLinkErrorLog)
ASSERT_GL_NO_ERROR();
}
// Validate error messages when the link mismatch occurs on the type of a non-struct varying.
TEST_P(GLSLTest, ErrorMessageOfVaryingMismatch)
{
const std::string &vertexShader =
R"(
attribute vec4 inputAttribute;
varying vec4 vertex_out;
void main()
{
vertex_out = inputAttribute;
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(
precision mediump float;
varying float vertex_out;
void main()
{
gl_FragColor = vec4(vertex_out, 0.0, 0.0, 1.0);
})";
validateComponentsInErrorMessage(vertexShader, fragmentShader, "Types", "varying 'vertex_out'");
}
// Validate error messages when the link mismatch occurs on the name of a varying field.
TEST_P(GLSLTest_ES3, ErrorMessageOfVaryingStructFieldNameMismatch)
{
const std::string &vertexShader =
R"(#version 300 es
in vec4 inputAttribute;
struct S {
float val1;
vec4 val2;
};
out S vertex_out;
void main()
{
vertex_out.val2 = inputAttribute;
vertex_out.val1 = inputAttribute[0];
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(#version 300 es
precision mediump float;
struct S {
float val1;
vec4 val3;
};
in S vertex_out;
layout (location = 0) out vec4 frag_out;
void main()
{
frag_out = vec4(vertex_out.val1, 0.0, 0.0, 1.0);
})";
validateComponentsInErrorMessage(vertexShader, fragmentShader, "Field names",
"varying 'vertex_out'");
}
// Validate error messages when the link mismatch occurs on the type of a varying field.
TEST_P(GLSLTest_ES3, ErrorMessageOfVaryingStructFieldMismatch)
{
const std::string &vertexShader =
R"(#version 300 es
in vec4 inputAttribute;
struct S {
float val1;
vec4 val2;
};
out S vertex_out;
void main()
{
vertex_out.val2 = inputAttribute;
vertex_out.val1 = inputAttribute[0];
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(#version 300 es
precision mediump float;
struct S {
float val1;
vec2 val2;
};
in S vertex_out;
layout (location = 0) out vec4 frag_out;
void main()
{
frag_out = vec4(vertex_out.val1, 0.0, 0.0, 1.0);
})";
validateComponentsInErrorMessage(vertexShader, fragmentShader, "Types",
"varying 'vertex_out' member 'vertex_out.val2'");
}
// Validate error messages when the link mismatch occurs on the name of a struct member of a uniform
// field.
TEST_P(GLSLTest, ErrorMessageOfLinkUniformStructFieldNameMismatch)
{
const std::string &vertexShader =
R"(
struct T
{
vec2 t1;
vec3 t2;
};
struct S {
T val1;
vec4 val2;
};
uniform S uni;
attribute vec4 inputAttribute;
varying vec4 vertex_out;
void main()
{
vertex_out = uni.val2;
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(
precision highp float;
struct T
{
vec2 t1;
vec3 t3;
};
struct S {
T val1;
vec4 val2;
};
uniform S uni;
varying vec4 vertex_out;
void main()
{
gl_FragColor = vec4(uni.val1.t1[0], 0.0, 0.0, 1.0);
})";
validateComponentsInErrorMessage(vertexShader, fragmentShader, "Field names",
"uniform 'uni' member 'uni.val1'");
}
// Validate error messages when the link mismatch occurs on the type of a non-struct uniform block
// field.
TEST_P(GLSLTest_ES3, ErrorMessageOfLinkInterfaceBlockFieldMismatch)
{
const std::string &vertexShader =
R"(#version 300 es
uniform S {
vec2 val1;
vec4 val2;
} uni;
in vec4 inputAttribute;
out vec4 vertex_out;
void main()
{
vertex_out = uni.val2;
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
uniform S {
vec2 val1;
vec3 val2;
} uni;
in vec4 vertex_out;
layout (location = 0) out vec4 frag_out;
void main()
{
frag_out = vec4(uni.val1[0], 0.0, 0.0, 1.0);
})";
validateComponentsInErrorMessage(vertexShader, fragmentShader, "Types",
"interface block 'S' member 'S.val2'");
}
// Validate error messages when the link mismatch occurs on the type of a member of a uniform block
// struct field.
TEST_P(GLSLTest_ES3, ErrorMessageOfLinkInterfaceBlockStructFieldMismatch)
{
const std::string &vertexShader =
R"(#version 300 es
struct T
{
vec2 t1;
vec3 t2;
};
uniform S {
T val1;
vec4 val2;
} uni;
in vec4 inputAttribute;
out vec4 vertex_out;
void main()
{
vertex_out = uni.val2;
gl_Position = inputAttribute;
})";
const std::string &fragmentShader =
R"(#version 300 es
precision highp float;
struct T
{
vec2 t1;
vec4 t2;
};
uniform S {
T val1;
vec4 val2;
} uni;
in vec4 vertex_out;
layout (location = 0) out vec4 frag_out;
void main()
{
frag_out = vec4(uni.val1.t1[0], 0.0, 0.0, 1.0);
})";
validateComponentsInErrorMessage(vertexShader, fragmentShader, "Types",
"interface block 'S' member 'S.val1.t2'");
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest,
ES2_D3D9(),
......
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