Commit 7a8fe156 by Jiawei Shao Committed by Commit Bot

ES31: Add link validation on MAX_COMBINED_SHADER_OUTPUT_RESOURCES

This patch adds the link validation on the maximum combined shader output resources required in OpenGL ES 3.1 SPEC. OpenGL ES 3.1 SPEC has restrictions on the sum of the number of all active images, shader storage blocks and fragment shader outputs. A link error will be generated if this sum exceeds the implementation- dependent value of MAX_COMBINED_SHADER_OUTPUT_RESOURCES. In order not to affect the existing image tests, this patch also sets a temporary value for maxCombinedShaderOutputResources on D3D11 back-ends. We will set more accurate values for all the UAV related resource limits in the next patch. BUG=angleproject:2345 TEST=dEQP-GLES31.functional.state_query.integer.max_combined_shader_output_resources_* Change-Id: Ib83a19ef0ae0b9af3422b5c970c7c07d96b2359d Reviewed-on: https://chromium-review.googlesource.com/1039155 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 41e59f55
...@@ -705,13 +705,16 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -705,13 +705,16 @@ class Program final : angle::NonCopyable, public LabeledObject
bool linkValidateShaders(const Context *context, InfoLog &infoLog); bool linkValidateShaders(const Context *context, InfoLog &infoLog);
bool linkAttributes(const Context *context, InfoLog &infoLog); bool linkAttributes(const Context *context, InfoLog &infoLog);
bool linkInterfaceBlocks(const Context *context, InfoLog &infoLog); bool linkInterfaceBlocks(const Context *context,
InfoLog &infoLog,
GLuint *combinedShaderStorageBlocksCount);
bool linkVaryings(const Context *context, InfoLog &infoLog) const; bool linkVaryings(const Context *context, InfoLog &infoLog) const;
bool linkUniforms(const Context *context, bool linkUniforms(const Context *context,
InfoLog &infoLog, InfoLog &infoLog,
const ProgramBindings &uniformLocationBindings); const ProgramBindings &uniformLocationBindings,
void linkSamplerAndImageBindings(); GLuint *combinedImageUniformsCount);
void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount);
bool linkAtomicCounterBuffers(); bool linkAtomicCounterBuffers();
void updateLinkedShaderStages(); void updateLinkedShaderStages();
...@@ -741,7 +744,9 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -741,7 +744,9 @@ class Program final : angle::NonCopyable, public LabeledObject
void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings); void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings);
ProgramMergedVaryings getMergedVaryings(const Context *context) const; ProgramMergedVaryings getMergedVaryings(const Context *context) const;
void linkOutputVariables(const Context *context); bool linkOutputVariables(const Context *context,
GLuint combinedImageUniformsCount,
GLuint combinedShaderStorageBlocksCount);
void setUniformValuesFromBindingQualifiers(); void setUniformValuesFromBindingQualifiers();
......
...@@ -46,6 +46,11 @@ ShaderType ActiveVariable::getFirstShaderTypeWhereActive() const ...@@ -46,6 +46,11 @@ ShaderType ActiveVariable::getFirstShaderTypeWhereActive() const
return static_cast<ShaderType>(gl::ScanForward(mActiveUseBits.bits())); return static_cast<ShaderType>(gl::ScanForward(mActiveUseBits.bits()));
} }
GLuint ActiveVariable::activeShaderCount() const
{
return static_cast<GLuint>(mActiveUseBits.count());
}
LinkedUniform::LinkedUniform() LinkedUniform::LinkedUniform()
: typeInfo(nullptr), bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo()) : typeInfo(nullptr), bufferIndex(-1), blockInfo(sh::BlockMemberInfo::getDefaultBlockInfo())
{ {
......
...@@ -32,6 +32,7 @@ struct ActiveVariable ...@@ -32,6 +32,7 @@ struct ActiveVariable
void setActive(ShaderType shaderType, bool used); void setActive(ShaderType shaderType, bool used);
void unionReferencesWith(const ActiveVariable &other); void unionReferencesWith(const ActiveVariable &other);
bool isActive(ShaderType shaderType) const; bool isActive(ShaderType shaderType) const;
GLuint activeShaderCount() const;
private: private:
ShaderBitSet mActiveUseBits; ShaderBitSet mActiveUseBits;
......
...@@ -957,6 +957,20 @@ size_t GetMaximumComputeImageUniforms(D3D_FEATURE_LEVEL featureLevel) ...@@ -957,6 +957,20 @@ size_t GetMaximumComputeImageUniforms(D3D_FEATURE_LEVEL featureLevel)
} }
} }
size_t GetMaximumCombinedShaderOutputResources(D3D_FEATURE_LEVEL featureLevel)
{
switch (featureLevel)
{
// TODO(jiawei.shao@intel.com): Get a more accurate limit. For now using the minimum
// requirement for GLES 3.1.
case D3D_FEATURE_LEVEL_11_1:
case D3D_FEATURE_LEVEL_11_0:
return 4;
default:
return 0;
}
}
int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel)
{ {
switch (featureLevel) switch (featureLevel)
...@@ -1396,6 +1410,8 @@ void GenerateCaps(ID3D11Device *device, ...@@ -1396,6 +1410,8 @@ void GenerateCaps(ID3D11Device *device,
caps->maxImageUnits = static_cast<GLuint>(GetMaximumImageUnits(featureLevel)); caps->maxImageUnits = static_cast<GLuint>(GetMaximumImageUnits(featureLevel));
caps->maxComputeImageUniforms = caps->maxComputeImageUniforms =
static_cast<GLuint>(GetMaximumComputeImageUniforms(featureLevel)); static_cast<GLuint>(GetMaximumComputeImageUniforms(featureLevel));
caps->maxCombinedShaderOutputResources =
static_cast<GLuint>(GetMaximumCombinedShaderOutputResources(featureLevel));
// Aggregate shader limits // Aggregate shader limits
caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks; caps->maxUniformBufferBindings = caps->maxVertexUniformBlocks + caps->maxFragmentUniformBlocks;
......
...@@ -70,7 +70,6 @@ ...@@ -70,7 +70,6 @@
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_shader_storage_buffer_bindings_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_shader_storage_buffer_bindings_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_shader_storage_block_size_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_shader_storage_block_size_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_combined_shader_storage_blocks_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_combined_shader_storage_blocks_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_combined_shader_output_resources_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_uniform_buffer_bindings_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_uniform_buffer_bindings_* = FAIL
1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_combined_texture_image_units_* = FAIL 1442 D3D11 : dEQP-GLES31.functional.state_query.integer.max_combined_texture_image_units_* = FAIL
1729 D3D11 : dEQP-GLES31.functional.state_query.indexed.atomic_counter_buffer_* = FAIL 1729 D3D11 : dEQP-GLES31.functional.state_query.indexed.atomic_counter_buffer_* = FAIL
......
...@@ -1209,6 +1209,75 @@ TEST_P(ComputeShaderTest, groupMemoryBarrierAndBarrierTest) ...@@ -1209,6 +1209,75 @@ TEST_P(ComputeShaderTest, groupMemoryBarrierAndBarrierTest)
} }
} }
// Verify that a link error is generated when the sum of the number of active image uniforms and
// active shader storage blocks in a compute shader exceeds GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
TEST_P(ComputeShaderTest, ExceedCombinedShaderOutputResourcesInCS)
{
// TODO(jiawei.shao@intel.com): enable this test when shader storage buffer is supported on
// D3D11 back-ends.
ANGLE_SKIP_TEST_IF(IsD3D11());
GLint maxCombinedShaderOutputResources;
GLint maxComputeShaderStorageBlocks;
GLint maxComputeImageUniforms;
glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &maxCombinedShaderOutputResources);
glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
ANGLE_SKIP_TEST_IF(maxCombinedShaderOutputResources >=
maxComputeShaderStorageBlocks + maxComputeImageUniforms);
std::ostringstream computeShaderStream;
computeShaderStream << "#version 310 es\n"
"layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;\n"
"layout(shared, binding = 0) buffer blockName"
"{\n"
" uint data;\n"
"} instance["
<< maxComputeShaderStorageBlocks << "];\n";
ASSERT_GE(maxComputeImageUniforms, 4);
int numImagesInArray = maxComputeImageUniforms / 2;
int numImagesNonArray = maxComputeImageUniforms - numImagesInArray;
for (int i = 0; i < numImagesNonArray; ++i)
{
computeShaderStream << "layout(r32f, binding = " << i << ") uniform highp image2D image"
<< i << ";\n";
}
computeShaderStream << "layout(r32f, binding = " << numImagesNonArray
<< ") uniform highp image2D imageArray[" << numImagesInArray << "];\n";
computeShaderStream << "void main()\n"
"{\n"
" uint val = 0u;\n"
" vec4 val2 = vec4(0.0);\n";
for (int i = 0; i < maxComputeShaderStorageBlocks; ++i)
{
computeShaderStream << " val += instance[" << i << "].data; \n";
}
for (int i = 0; i < numImagesNonArray; ++i)
{
computeShaderStream << " val2 += imageLoad(image" << i
<< ", ivec2(gl_LocalInvocationID.xy)); \n";
}
for (int i = 0; i < numImagesInArray; ++i)
{
computeShaderStream << " val2 += imageLoad(imageArray[" << i << "]"
<< ", ivec2(gl_LocalInvocationID.xy)); \n";
}
computeShaderStream << " instance[0].data = val + uint(val2.x);\n"
"}\n";
GLuint computeProgram = CompileComputeProgram(computeShaderStream.str());
EXPECT_EQ(0u, computeProgram);
}
// Check that it is not possible to create a compute shader when the context does not support ES // Check that it is not possible to create a compute shader when the context does not support ES
// 3.10 // 3.10
TEST_P(ComputeShaderTestES3, NotSupported) TEST_P(ComputeShaderTestES3, NotSupported)
......
...@@ -4133,6 +4133,126 @@ TEST_P(GLSLTest_ES3, NestedFloorWithLargeMultiplierInside) ...@@ -4133,6 +4133,126 @@ TEST_P(GLSLTest_ES3, NestedFloorWithLargeMultiplierInside)
EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() - 1, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() - 1, GLColor::green);
} }
// Verify that a link error is generated when the sum of the number of active image uniforms and
// active shader storage blocks in a rendering pipeline exceeds
// GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
TEST_P(GLSLTest_ES31, ExceedCombinedShaderOutputResourcesInVSAndFS)
{
// TODO(jiawei.shao@intel.com): enable this test when shader storage buffer is supported on
// D3D11 back-ends.
ANGLE_SKIP_TEST_IF(IsD3D11());
GLint maxVertexShaderStorageBlocks;
GLint maxVertexImageUniforms;
GLint maxFragmentShaderStorageBlocks;
GLint maxFragmentImageUniforms;
GLint maxCombinedShaderStorageBlocks;
GLint maxCombinedImageUniforms;
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &maxVertexShaderStorageBlocks);
glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &maxVertexImageUniforms);
glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragmentShaderStorageBlocks);
glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &maxFragmentImageUniforms);
glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxCombinedShaderStorageBlocks);
glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &maxCombinedImageUniforms);
ASSERT_GE(maxCombinedShaderStorageBlocks, maxVertexShaderStorageBlocks);
ASSERT_GE(maxCombinedShaderStorageBlocks, maxFragmentShaderStorageBlocks);
ASSERT_GE(maxCombinedImageUniforms, maxVertexImageUniforms);
ASSERT_GE(maxCombinedImageUniforms, maxFragmentImageUniforms);
GLint vertexSSBOs = maxVertexShaderStorageBlocks;
GLint fragmentSSBOs = maxFragmentShaderStorageBlocks;
// Limit the sum of ssbos in vertex and fragment shaders to maxCombinedShaderStorageBlocks.
if (vertexSSBOs + fragmentSSBOs > maxCombinedShaderStorageBlocks)
{
fragmentSSBOs = maxCombinedShaderStorageBlocks - vertexSSBOs;
}
GLint vertexImages = maxVertexImageUniforms;
GLint fragmentImages = maxFragmentImageUniforms;
// Limit the sum of images in vertex and fragment shaders to maxCombinedImageUniforms.
if (vertexImages + fragmentImages > maxCombinedImageUniforms)
{
vertexImages = maxCombinedImageUniforms - fragmentImages;
}
GLint maxDrawBuffers;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
GLint maxCombinedShaderOutputResources;
glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &maxCombinedShaderOutputResources);
ASSERT_GL_NO_ERROR();
ANGLE_SKIP_TEST_IF(vertexSSBOs + fragmentSSBOs + vertexImages + fragmentImages +
maxDrawBuffers <=
maxCombinedShaderOutputResources);
std::ostringstream vertexStream;
vertexStream << "#version 310 es\n";
for (int i = 0; i < vertexSSBOs; ++i)
{
vertexStream << "layout(shared, binding = " << i << ") buffer blockName" << i
<< "{\n"
" float data;\n"
"} ssbo"
<< i << ";\n";
}
vertexStream << "layout(r32f, binding = 0) uniform highp image2D imageArray[" << vertexImages
<< "];\n";
vertexStream << "void main()\n"
"{\n"
" float val = 0.1;\n"
" vec4 val2 = vec4(0.0);\n";
for (int i = 0; i < vertexSSBOs; ++i)
{
vertexStream << " val += ssbo" << i << ".data; \n";
}
for (int i = 0; i < vertexImages; ++i)
{
vertexStream << " val2 += imageLoad(imageArray[" << i << "], ivec2(0, 0)); \n";
}
vertexStream << " gl_Position = vec4(val, val2);\n"
"}\n";
std::ostringstream fragmentStream;
fragmentStream << "#version 310 es\n"
<< "precision highp float;\n";
for (int i = 0; i < fragmentSSBOs; ++i)
{
fragmentStream << "layout(shared, binding = " << i << ") buffer blockName" << i
<< "{\n"
" float data;\n"
"} ssbo"
<< i << ";\n";
}
fragmentStream << "layout(r32f, binding = 0) uniform highp image2D imageArray["
<< fragmentImages << "];\n";
fragmentStream << "layout (location = 0) out vec4 foutput[" << maxDrawBuffers << "];\n";
fragmentStream << "void main()\n"
"{\n"
" float val = 0.1;\n"
" vec4 val2 = vec4(0.0);\n";
for (int i = 0; i < fragmentSSBOs; ++i)
{
fragmentStream << " val += ssbo" << i << ".data; \n";
}
for (int i = 0; i < fragmentImages; ++i)
{
fragmentStream << " val2 += imageLoad(imageArray[" << i << "], ivec2(0, 0)); \n";
}
for (int i = 0; i < maxDrawBuffers; ++i)
{
fragmentStream << " foutput[" << i << "] = vec4(val, val2);\n";
}
fragmentStream << "}\n";
GLuint program = CompileProgram(vertexStream.str(), fragmentStream.str());
EXPECT_EQ(0u, program);
ASSERT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest, ANGLE_INSTANTIATE_TEST(GLSLTest,
......
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