Commit 84aa2dcf by Martin Radev Committed by Commit Bot

Add textureGather and textureGatherOffset

The patch adds new built-ins and extends the semantic parser to add support for textureGather and textureGatherOffset. BUG=angleproject:1442 TEST=angle_unittests TEST=angle_deqp_gles31_tests.exe --deqp-case=dEQP-GLES31.functional.texture.gather* --deqp-egl-display-type=angle-gl Change-Id: Iaf98c3420fbd61193072fdec8f5a61ac4c574101 Reviewed-on: https://chromium-review.googlesource.com/660124 Commit-Queue: Martin Radev <mradev@nvidia.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 72f58fa3
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 181 #define ANGLE_SH_VERSION 182
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -343,6 +343,10 @@ struct ShBuiltInResources ...@@ -343,6 +343,10 @@ struct ShBuiltInResources
// GLES 3.1 constants // GLES 3.1 constants
// texture gather offset constraints.
int MinProgramTextureGatherOffset;
int MaxProgramTextureGatherOffset;
// maximum number of available image units // maximum number of available image units
int MaxImageUnits; int MaxImageUnits;
......
...@@ -721,6 +721,8 @@ void TCompiler::setResourceString() ...@@ -721,6 +721,8 @@ void TCompiler::setResourceString()
<< ":MaxViewsOVR:" << compileResources.MaxViewsOVR << ":MaxViewsOVR:" << compileResources.MaxViewsOVR
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
<< ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
<< ":MinProgramTextureGatherOffset:" << compileResources.MinProgramTextureGatherOffset
<< ":MaxProgramTextureGatherOffset:" << compileResources.MaxProgramTextureGatherOffset
<< ":MaxImageUnits:" << compileResources.MaxImageUnits << ":MaxImageUnits:" << compileResources.MaxImageUnits
<< ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms << ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms
<< ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms << ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms
......
...@@ -666,6 +666,39 @@ void InsertBuiltInFunctions(sh::GLenum type, ...@@ -666,6 +666,39 @@ void InsertBuiltInFunctions(sh::GLenum type,
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "texelFetch", gsampler2DMS, int2, int1); symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "texelFetch", gsampler2DMS, int2, int1);
// Insert all variations of textureGather.
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2D, float2);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2D, float2, int1);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2DArray, float3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsampler2DArray, float3,
int1);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsamplerCube, float3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGather", gsamplerCube, float3, int1);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DShadow, float2);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DShadow, float2,
float1);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DArrayShadow,
float3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", sampler2DArrayShadow,
float3, float1);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", samplerCubeShadow, float3);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGather", samplerCubeShadow, float3,
float1);
// Insert all variations of textureGatherOffset.
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2D, float2,
int2);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2D, float2,
int2, int1);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2DArray,
float3, int2);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, gvec4, "textureGatherOffset", gsampler2DArray,
float3, int2, int1);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGatherOffset", sampler2DShadow,
float2, float1, int2);
symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, float4, "textureGatherOffset", sampler2DArrayShadow,
float3, float1, int2);
if (type == GL_COMPUTE_SHADER) if (type == GL_COMPUTE_SHADER)
{ {
symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpBarrier, voidType, symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpBarrier, voidType,
......
...@@ -189,6 +189,8 @@ TParseContext::TParseContext(TSymbolTable &symt, ...@@ -189,6 +189,8 @@ TParseContext::TParseContext(TSymbolTable &symt,
mUsesSecondaryOutputs(false), mUsesSecondaryOutputs(false),
mMinProgramTexelOffset(resources.MinProgramTexelOffset), mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset), mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
mMinProgramTextureGatherOffset(resources.MinProgramTextureGatherOffset),
mMaxProgramTextureGatherOffset(resources.MaxProgramTextureGatherOffset),
mComputeShaderLocalSizeDeclared(false), mComputeShaderLocalSizeDeclared(false),
mNumViews(-1), mNumViews(-1),
mMaxNumViews(resources.MaxViewsOVR), mMaxNumViews(resources.MaxViewsOVR),
...@@ -5267,12 +5269,79 @@ TIntermBranch *TParseContext::addBranch(TOperator op, ...@@ -5267,12 +5269,79 @@ TIntermBranch *TParseContext::addBranch(TOperator op,
return node; return node;
} }
void TParseContext::checkTextureGather(TIntermAggregate *functionCall)
{
ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
const TString &name = functionCall->getFunctionSymbolInfo()->getName();
bool isTextureGather = (name == "textureGather");
bool isTextureGatherOffset = (name == "textureGatherOffset");
if (isTextureGather || isTextureGatherOffset)
{
TIntermNode *componentNode = nullptr;
TIntermSequence *arguments = functionCall->getSequence();
ASSERT(arguments->size() >= 2u && arguments->size() <= 4u);
const TIntermTyped *sampler = arguments->front()->getAsTyped();
ASSERT(sampler != nullptr);
switch (sampler->getBasicType())
{
case EbtSampler2D:
case EbtISampler2D:
case EbtUSampler2D:
case EbtSampler2DArray:
case EbtISampler2DArray:
case EbtUSampler2DArray:
if ((isTextureGather && arguments->size() == 3u) ||
(isTextureGatherOffset && arguments->size() == 4u))
{
componentNode = arguments->back();
}
break;
case EbtSamplerCube:
case EbtISamplerCube:
case EbtUSamplerCube:
ASSERT(!isTextureGatherOffset);
if (arguments->size() == 3u)
{
componentNode = arguments->back();
}
break;
case EbtSampler2DShadow:
case EbtSampler2DArrayShadow:
case EbtSamplerCubeShadow:
break;
default:
UNREACHABLE();
break;
}
if (componentNode)
{
const TIntermConstantUnion *componentConstantUnion =
componentNode->getAsConstantUnion();
if (componentNode->getAsTyped()->getQualifier() != EvqConst || !componentConstantUnion)
{
error(functionCall->getLine(), "Texture component must be a constant expression",
name.c_str());
}
else
{
int component = componentConstantUnion->getIConst(0);
if (component < 0 || component > 3)
{
error(functionCall->getLine(), "Component must be in the range [0;3]",
name.c_str());
}
}
}
}
}
void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
{ {
ASSERT(functionCall->getOp() == EOpCallBuiltInFunction); ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
const TString &name = functionCall->getFunctionSymbolInfo()->getName(); const TString &name = functionCall->getFunctionSymbolInfo()->getName();
TIntermNode *offset = nullptr; TIntermNode *offset = nullptr;
TIntermSequence *arguments = functionCall->getSequence(); TIntermSequence *arguments = functionCall->getSequence();
bool useTextureGatherOffsetConstraints = false;
if (name == "texelFetchOffset" || name == "textureLodOffset" || if (name == "texelFetchOffset" || name == "textureLodOffset" ||
name == "textureProjLodOffset" || name == "textureGradOffset" || name == "textureProjLodOffset" || name == "textureGradOffset" ||
name == "textureProjGradOffset") name == "textureProjGradOffset")
...@@ -5285,6 +5354,31 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) ...@@ -5285,6 +5354,31 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
ASSERT(arguments->size() >= 3); ASSERT(arguments->size() >= 3);
offset = (*arguments)[2]; offset = (*arguments)[2];
} }
else if (name == "textureGatherOffset")
{
ASSERT(arguments->size() >= 3u);
const TIntermTyped *sampler = arguments->front()->getAsTyped();
ASSERT(sampler != nullptr);
switch (sampler->getBasicType())
{
case EbtSampler2D:
case EbtISampler2D:
case EbtUSampler2D:
case EbtSampler2DArray:
case EbtISampler2DArray:
case EbtUSampler2DArray:
offset = (*arguments)[2];
break;
case EbtSampler2DShadow:
case EbtSampler2DArrayShadow:
offset = (*arguments)[3];
break;
default:
UNREACHABLE();
break;
}
useTextureGatherOffsetConstraints = true;
}
if (offset != nullptr) if (offset != nullptr)
{ {
TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion(); TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
...@@ -5298,10 +5392,14 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall) ...@@ -5298,10 +5392,14 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
ASSERT(offsetConstantUnion->getBasicType() == EbtInt); ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
size_t size = offsetConstantUnion->getType().getObjectSize(); size_t size = offsetConstantUnion->getType().getObjectSize();
const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer(); const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer();
int minOffsetValue = useTextureGatherOffsetConstraints ? mMinProgramTextureGatherOffset
: mMinProgramTexelOffset;
int maxOffsetValue = useTextureGatherOffsetConstraints ? mMaxProgramTextureGatherOffset
: mMaxProgramTexelOffset;
for (size_t i = 0u; i < size; ++i) for (size_t i = 0u; i < size; ++i)
{ {
int offsetValue = values[i].getIConst(); int offsetValue = values[i].getIConst();
if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset) if (offsetValue > maxOffsetValue || offsetValue < minOffsetValue)
{ {
std::stringstream tokenStream; std::stringstream tokenStream;
tokenStream << offsetValue; tokenStream << offsetValue;
...@@ -5547,6 +5645,7 @@ TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunction *fnCall, ...@@ -5547,6 +5645,7 @@ TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunction *fnCall,
{ {
callNode = TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, arguments); callNode = TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, arguments);
checkTextureOffsetConst(callNode); checkTextureOffsetConst(callNode);
checkTextureGather(callNode);
checkImageMemoryAccessForBuiltinFunctions(callNode); checkImageMemoryAccessForBuiltinFunctions(callNode);
} }
else else
......
...@@ -392,6 +392,7 @@ class TParseContext : angle::NonCopyable ...@@ -392,6 +392,7 @@ class TParseContext : angle::NonCopyable
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc); TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc); TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc);
void checkTextureGather(TIntermAggregate *functionCall);
void checkTextureOffsetConst(TIntermAggregate *functionCall); void checkTextureOffsetConst(TIntermAggregate *functionCall);
void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall); void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall);
void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition, void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
...@@ -576,6 +577,9 @@ class TParseContext : angle::NonCopyable ...@@ -576,6 +577,9 @@ class TParseContext : angle::NonCopyable
int mMinProgramTexelOffset; int mMinProgramTexelOffset;
int mMaxProgramTexelOffset; int mMaxProgramTexelOffset;
int mMinProgramTextureGatherOffset;
int mMaxProgramTextureGatherOffset;
// keep track of local group size declared in layout. It should be declared only once. // keep track of local group size declared in layout. It should be declared only once.
bool mComputeShaderLocalSizeDeclared; bool mComputeShaderLocalSizeDeclared;
sh::WorkGroupSize mComputeShaderLocalSize; sh::WorkGroupSize mComputeShaderLocalSize;
......
...@@ -202,6 +202,14 @@ void InitBuiltInResources(ShBuiltInResources *resources) ...@@ -202,6 +202,14 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->MaxFunctionParameters = 1024; resources->MaxFunctionParameters = 1024;
// ES 3.1 Revision 4, 7.2 Built-in Constants // ES 3.1 Revision 4, 7.2 Built-in Constants
// ES 3.1, Revision 4, 8.13 Texture minification
// "The value of MIN_PROGRAM_TEXTURE_GATHER_OFFSET must be less than or equal to the value of
// MIN_PROGRAM_TEXEL_OFFSET. The value of MAX_PROGRAM_TEXTURE_GATHER_OFFSET must be greater than
// or equal to the value of MAX_PROGRAM_TEXEL_OFFSET"
resources->MinProgramTextureGatherOffset = -8;
resources->MaxProgramTextureGatherOffset = 7;
resources->MaxImageUnits = 4; resources->MaxImageUnits = 4;
resources->MaxVertexImageUniforms = 0; resources->MaxVertexImageUniforms = 0;
resources->MaxFragmentImageUniforms = 0; resources->MaxFragmentImageUniforms = 0;
......
...@@ -88,6 +88,8 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state) ...@@ -88,6 +88,8 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state)
mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset; mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset;
// GLSL ES 3.1 constants // GLSL ES 3.1 constants
mResources.MaxProgramTextureGatherOffset = caps.maxProgramTextureGatherOffset;
mResources.MinProgramTextureGatherOffset = caps.minProgramTextureGatherOffset;
mResources.MaxImageUnits = caps.maxImageUnits; mResources.MaxImageUnits = caps.maxImageUnits;
mResources.MaxVertexImageUniforms = caps.maxVertexImageUniforms; mResources.MaxVertexImageUniforms = caps.maxVertexImageUniforms;
mResources.MaxFragmentImageUniforms = caps.maxFragmentImageUniforms; mResources.MaxFragmentImageUniforms = caps.maxFragmentImageUniforms;
......
...@@ -4751,3 +4751,86 @@ TEST_F(FragmentShaderValidationTest, AssignValueToCentroidIn) ...@@ -4751,3 +4751,86 @@ TEST_F(FragmentShaderValidationTest, AssignValueToCentroidIn)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
} }
} }
// Test that shader compilation fails if the component argument is dynamic.
TEST_F(FragmentShaderValidationTest, DynamicComponentTextureGather)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump sampler2D;\n"
"uniform sampler2D tex;\n"
"out vec4 o_color;\n"
"uniform int uComp;\n"
"void main()\n"
"{\n"
" o_color = textureGather(tex, vec2(0), uComp);"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that shader compilation fails if the component argument to textureGather has a negative
// value.
TEST_F(FragmentShaderValidationTest, TextureGatherNegativeComponent)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump sampler2D;\n"
"uniform sampler2D tex;\n"
"out vec4 o_color;\n"
"void main()\n"
"{\n"
" o_color = textureGather(tex, vec2(0), -1);"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that shader compilation fails if the component argument to textureGather has a value greater
// than 3.
TEST_F(FragmentShaderValidationTest, TextureGatherTooGreatComponent)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump sampler2D;\n"
"uniform sampler2D tex;\n"
"out vec4 o_color;\n"
"void main()\n"
"{\n"
" o_color = textureGather(tex, vec2(0), 4);"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that shader compilation fails if the offset is less than the minimum value.
TEST_F(FragmentShaderValidationTest, TextureGatherTooGreatOffset)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump sampler2D;\n"
"uniform sampler2D tex;\n"
"out vec4 o_color;\n"
"void main()\n"
"{\n"
" o_color = textureGatherOffset(tex, vec2(0), ivec2(-100), 2);"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
\ No newline at end of file
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.type.vertex_fragment.struct.* = SKIP 1442 OPENGL D3D11 : dEQP-GLES31.functional.program_interface_query.transform_feedback_varying.type.vertex_fragment.struct.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.vertex_attribute_binding.* = SKIP 1442 D3D11 : dEQP-GLES31.functional.vertex_attribute_binding.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.stencil_texturing.* = SKIP 1442 D3D11 : dEQP-GLES31.functional.stencil_texturing.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.texture.gather.* = SKIP
// OpenGL Failing Tests // OpenGL Failing Tests
1442 OPENGL : dEQP-GLES31.functional.shaders.builtin_functions.texture_size.samples_1_texture_2d_array = FAIL 1442 OPENGL : dEQP-GLES31.functional.shaders.builtin_functions.texture_size.samples_1_texture_2d_array = FAIL
...@@ -1237,7 +1238,6 @@ ...@@ -1237,7 +1238,6 @@
1442 OPENGL D3D11 : dEQP-GLES31.functional.stencil_texturing.render.depth24_stencil8_draw = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.stencil_texturing.render.depth24_stencil8_draw = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.stencil_texturing.misc.compare_mode_effect = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.stencil_texturing.misc.compare_mode_effect = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.stencil_texturing.misc.base_level = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.stencil_texturing.misc.base_level = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.texture.gather.* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.boolean.sample_mask_* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.boolean.sample_mask_* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.integer.dispatch_indirect_buffer_binding_* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.integer.dispatch_indirect_buffer_binding_* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.integer.program_pipeline_binding_* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.state_query.integer.program_pipeline_binding_* = FAIL
......
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