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 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 181
#define ANGLE_SH_VERSION 182
enum ShShaderSpec
{
......@@ -343,6 +343,10 @@ struct ShBuiltInResources
// GLES 3.1 constants
// texture gather offset constraints.
int MinProgramTextureGatherOffset;
int MaxProgramTextureGatherOffset;
// maximum number of available image units
int MaxImageUnits;
......
......@@ -721,6 +721,8 @@ void TCompiler::setResourceString()
<< ":MaxViewsOVR:" << compileResources.MaxViewsOVR
<< ":NV_draw_buffers:" << compileResources.NV_draw_buffers
<< ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
<< ":MinProgramTextureGatherOffset:" << compileResources.MinProgramTextureGatherOffset
<< ":MaxProgramTextureGatherOffset:" << compileResources.MaxProgramTextureGatherOffset
<< ":MaxImageUnits:" << compileResources.MaxImageUnits
<< ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms
<< ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms
......
......@@ -666,6 +666,39 @@ void InsertBuiltInFunctions(sh::GLenum type,
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)
{
symbolTable.insertBuiltInFunctionNoParameters(ESSL3_1_BUILTINS, EOpBarrier, voidType,
......
......@@ -189,6 +189,8 @@ TParseContext::TParseContext(TSymbolTable &symt,
mUsesSecondaryOutputs(false),
mMinProgramTexelOffset(resources.MinProgramTexelOffset),
mMaxProgramTexelOffset(resources.MaxProgramTexelOffset),
mMinProgramTextureGatherOffset(resources.MinProgramTextureGatherOffset),
mMaxProgramTextureGatherOffset(resources.MaxProgramTextureGatherOffset),
mComputeShaderLocalSizeDeclared(false),
mNumViews(-1),
mMaxNumViews(resources.MaxViewsOVR),
......@@ -5267,12 +5269,79 @@ TIntermBranch *TParseContext::addBranch(TOperator op,
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)
{
ASSERT(functionCall->getOp() == EOpCallBuiltInFunction);
const TString &name = functionCall->getFunctionSymbolInfo()->getName();
TIntermNode *offset = nullptr;
TIntermSequence *arguments = functionCall->getSequence();
bool useTextureGatherOffsetConstraints = false;
if (name == "texelFetchOffset" || name == "textureLodOffset" ||
name == "textureProjLodOffset" || name == "textureGradOffset" ||
name == "textureProjGradOffset")
......@@ -5285,6 +5354,31 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
ASSERT(arguments->size() >= 3);
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)
{
TIntermConstantUnion *offsetConstantUnion = offset->getAsConstantUnion();
......@@ -5298,10 +5392,14 @@ void TParseContext::checkTextureOffsetConst(TIntermAggregate *functionCall)
ASSERT(offsetConstantUnion->getBasicType() == EbtInt);
size_t size = offsetConstantUnion->getType().getObjectSize();
const TConstantUnion *values = offsetConstantUnion->getUnionArrayPointer();
int minOffsetValue = useTextureGatherOffsetConstraints ? mMinProgramTextureGatherOffset
: mMinProgramTexelOffset;
int maxOffsetValue = useTextureGatherOffsetConstraints ? mMaxProgramTextureGatherOffset
: mMaxProgramTexelOffset;
for (size_t i = 0u; i < size; ++i)
{
int offsetValue = values[i].getIConst();
if (offsetValue > mMaxProgramTexelOffset || offsetValue < mMinProgramTexelOffset)
if (offsetValue > maxOffsetValue || offsetValue < minOffsetValue)
{
std::stringstream tokenStream;
tokenStream << offsetValue;
......@@ -5547,6 +5645,7 @@ TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunction *fnCall,
{
callNode = TIntermAggregate::CreateBuiltInFunctionCall(*fnCandidate, arguments);
checkTextureOffsetConst(callNode);
checkTextureGather(callNode);
checkImageMemoryAccessForBuiltinFunctions(callNode);
}
else
......
......@@ -392,6 +392,7 @@ class TParseContext : angle::NonCopyable
TIntermBranch *addBranch(TOperator op, const TSourceLoc &loc);
TIntermBranch *addBranch(TOperator op, TIntermTyped *expression, const TSourceLoc &loc);
void checkTextureGather(TIntermAggregate *functionCall);
void checkTextureOffsetConst(TIntermAggregate *functionCall);
void checkImageMemoryAccessForBuiltinFunctions(TIntermAggregate *functionCall);
void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
......@@ -576,6 +577,9 @@ class TParseContext : angle::NonCopyable
int mMinProgramTexelOffset;
int mMaxProgramTexelOffset;
int mMinProgramTextureGatherOffset;
int mMaxProgramTextureGatherOffset;
// keep track of local group size declared in layout. It should be declared only once.
bool mComputeShaderLocalSizeDeclared;
sh::WorkGroupSize mComputeShaderLocalSize;
......
......@@ -202,6 +202,14 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->MaxFunctionParameters = 1024;
// 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->MaxVertexImageUniforms = 0;
resources->MaxFragmentImageUniforms = 0;
......
......@@ -88,6 +88,8 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const ContextState &state)
mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset;
// GLSL ES 3.1 constants
mResources.MaxProgramTextureGatherOffset = caps.maxProgramTextureGatherOffset;
mResources.MinProgramTextureGatherOffset = caps.minProgramTextureGatherOffset;
mResources.MaxImageUnits = caps.maxImageUnits;
mResources.MaxVertexImageUniforms = caps.maxVertexImageUniforms;
mResources.MaxFragmentImageUniforms = caps.maxFragmentImageUniforms;
......
......@@ -4751,3 +4751,86 @@ TEST_F(FragmentShaderValidationTest, AssignValueToCentroidIn)
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 @@
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.stencil_texturing.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.texture.gather.* = SKIP
// OpenGL Failing Tests
1442 OPENGL : dEQP-GLES31.functional.shaders.builtin_functions.texture_size.samples_1_texture_2d_array = FAIL
......@@ -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.misc.compare_mode_effect = 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.integer.dispatch_indirect_buffer_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