Vulkan: Add OES_shader_multisample_interpolation support

Support OES_shader_multisample_interpolation extension if
maxInterpolationOffset >= 0.5

Bug: angleproject:3589
Tests: dEQP-GLES31.functional.shaders.multisample_interpolation.*
       dEQP-GLES31.functional.state_query.multisample_interpolation.*
Change-Id: I42997f10be82e3be8b63c56833cbbf791bf4be9b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2477905
Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Mohan Maiya 2020-10-23 12:52:34 -07:00 коммит произвёл Commit Bot
Родитель 5c4c37dcd4
Коммит 5d0458fa5c
18 изменённых файлов: 154 добавлений и 3 удалений

Просмотреть файл

@ -28,6 +28,7 @@ enum InterpolationType
{
INTERPOLATION_SMOOTH,
INTERPOLATION_CENTROID,
INTERPOLATION_SAMPLE,
INTERPOLATION_FLAT,
INTERPOLATION_NOPERSPECTIVE
};

Просмотреть файл

@ -981,10 +981,12 @@ enum TQualifier
EvqFlatOut,
EvqNoPerspectiveOut,
EvqCentroidOut, // Implies smooth
EvqSampleOut,
EvqSmoothIn,
EvqFlatIn,
EvqNoPerspectiveIn,
EvqCentroidIn, // Implies smooth
EvqSampleIn,
// GLSL ES 3.1 compute shader special variables
EvqShared,
@ -1042,6 +1044,7 @@ inline bool IsShaderIn(TQualifier qualifier)
case EvqFlatIn:
case EvqNoPerspectiveIn:
case EvqCentroidIn:
case EvqSampleIn:
return true;
default:
return false;
@ -1060,6 +1063,7 @@ inline bool IsShaderOut(TQualifier qualifier)
case EvqFlatOut:
case EvqNoPerspectiveOut:
case EvqCentroidOut:
case EvqSampleOut:
return true;
default:
return false;
@ -1333,6 +1337,9 @@ inline const char *getQualifierString(TQualifier q)
case EvqPerVertexIn: return "gl_in";
case EvqPrecise: return "precise";
case EvqClipDistance: return "ClipDistance";
case EvqSample: return "sample";
case EvqSampleIn: return "sample in";
case EvqSampleOut: return "sample out";
default: UNREACHABLE(); return "unknown qualifier";
}
// clang-format on

Просмотреть файл

@ -732,6 +732,7 @@ ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &var
case EvqNoPerspectiveOut:
case EvqCentroidOut:
case EvqGeometryOut:
case EvqSampleOut:
if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())
{
varying.isInvariant = true;

Просмотреть файл

@ -1090,6 +1090,7 @@ void TCompiler::setResourceString()
<< ":OES_texture_cube_map_array:" << mResources.OES_texture_cube_map_array
<< ":EXT_texture_cube_map_array:" << mResources.EXT_texture_cube_map_array
<< ":EXT_shadow_samplers:" << mResources.EXT_shadow_samplers
<< ":OES_shader_multisample_interpolation:" << mResources.OES_shader_multisample_interpolation
<< ":MinProgramTextureGatherOffset:" << mResources.MinProgramTextureGatherOffset
<< ":MaxProgramTextureGatherOffset:" << mResources.MaxProgramTextureGatherOffset
<< ":MaxImageUnits:" << mResources.MaxImageUnits

Просмотреть файл

@ -129,6 +129,10 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi
{
extBehavior[TExtension::EXT_shadow_samplers] = EBhUndefined;
}
if (resources.OES_shader_multisample_interpolation)
{
extBehavior[TExtension::OES_shader_multisample_interpolation] = EBhUndefined;
}
}
void ResetExtensionBehavior(const ShBuiltInResources &resources,

Просмотреть файл

@ -128,6 +128,26 @@ bool IsBufferOrSharedVariable(TIntermTyped *var)
return false;
}
TIntermTyped *FindLValueBase(TIntermTyped *node)
{
do
{
const TIntermBinary *binary = node->getAsBinaryNode();
if (binary == nullptr)
{
return node;
}
TOperator op = binary->getOp();
if (op != EOpIndexDirect && op != EOpIndexIndirect)
{
return static_cast<TIntermTyped *>(nullptr);
}
node = binary->getLeft();
} while (true);
}
} // namespace
// This tracks each binding point's current default offset for inheritance of subsequent
@ -534,6 +554,7 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
case EvqNoPerspectiveIn:
case EvqSmoothIn:
case EvqCentroidIn:
case EvqSampleIn:
message = "can't modify an input";
break;
case EvqUniform:
@ -5983,6 +6004,41 @@ void TParseContext::checkSingleTextureOffset(const TSourceLoc &line,
}
}
void TParseContext::checkInterpolationFS(TIntermAggregate *functionCall)
{
const TFunction *func = functionCall->getFunction();
if (!BuiltInGroup::isInterpolationFS(func))
{
return;
}
TIntermTyped *arg0 = nullptr;
if (functionCall->getAsAggregate())
{
const TIntermSequence *argp = functionCall->getSequence();
if (argp->size() > 0)
arg0 = (*argp)[0]->getAsTyped();
}
else
{
assert(functionCall->getAsUnaryNode());
arg0 = functionCall->getAsUnaryNode()->getOperand();
}
// Make sure the first argument is an interpolant, or an array element of an interpolant
if (!IsVaryingIn(arg0->getType().getQualifier()))
{
// It might still be an array element.
const TIntermTyped *base = FindLValueBase(arg0);
if (base == nullptr || (!IsVaryingIn(base->getType().getQualifier())))
error(arg0->getLine(),
"first argument must be an interpolant, or interpolant-array element",
func->name());
}
}
void TParseContext::checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall)
{
const TFunction *func = functionCall->getFunction();
@ -6248,6 +6304,7 @@ TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunctionLookup *fnCa
callNode->setLine(loc);
checkTextureOffset(callNode);
checkTextureGather(callNode);
checkInterpolationFS(callNode);
checkImageMemoryAccessForBuiltinFunctions(callNode);
functionCallRValueLValueErrorCheck(fnCandidate, callNode);
return callNode;

Просмотреть файл

@ -441,6 +441,7 @@ class TParseContext : angle::NonCopyable
void checkImageMemoryAccessForUserDefinedFunctions(const TFunction *functionDefinition,
const TIntermAggregate *functionCall);
void checkAtomicMemoryBuiltinFunctions(TIntermAggregate *functionCall);
void checkInterpolationFS(TIntermAggregate *functionCall);
// fnCall is only storing the built-in op, and function name or constructor type. arguments
// has the arguments.

Просмотреть файл

@ -440,6 +440,23 @@ bool JoinVariableStorageQualifier(TQualifier *joinedQualifier, TQualifier storag
}
break;
}
case EvqSample:
{
switch (storageQualifier)
{
case EvqVertexOut:
case EvqGeometryOut:
*joinedQualifier = EvqSampleOut;
break;
case EvqFragmentIn:
case EvqGeometryIn:
*joinedQualifier = EvqSampleIn;
break;
default:
return false;
}
break;
}
default:
return false;
}

Просмотреть файл

@ -1063,6 +1063,8 @@ const char *InterpolationString(TQualifier qualifier)
return "nointerpolation";
case EvqCentroidOut:
return "centroid";
case EvqSampleIn:
return "sample";
default:
UNREACHABLE();
}
@ -1083,6 +1085,8 @@ const char *QualifierString(TQualifier qualifier)
return "inout";
case EvqConstReadOnly:
return "const";
case EvqSampleOut:
return "sample";
default:
UNREACHABLE();
}

Просмотреть файл

@ -35,6 +35,7 @@ bool IsInterpolationIn(TQualifier qualifier)
case EvqFlatIn:
case EvqNoPerspectiveIn:
case EvqCentroidIn:
case EvqSampleIn:
return true;
default:
return false;
@ -538,6 +539,7 @@ bool IsVaryingOut(TQualifier qualifier)
case EvqCentroidOut:
case EvqVertexOut:
case EvqGeometryOut:
case EvqSampleOut:
return true;
default:
@ -558,6 +560,7 @@ bool IsVaryingIn(TQualifier qualifier)
case EvqCentroidIn:
case EvqFragmentIn:
case EvqGeometryIn:
case EvqSampleIn:
return true;
default:
@ -604,6 +607,9 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
case EvqCentroidOut:
return INTERPOLATION_CENTROID;
case EvqSampleIn:
case EvqSampleOut:
return INTERPOLATION_SAMPLE;
default:
UNREACHABLE();
#if !UNREACHABLE_IS_NORETURN

Просмотреть файл

@ -1036,6 +1036,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_EXT_buffer_storage"] = enableableExtension(&Extensions::bufferStorageEXT);
map["GL_OES_texture_stencil8"] = enableableExtension(&Extensions::stencilIndex8);
map["GL_OES_sample_shading"] = enableableExtension(&Extensions::sampleShadingOES);
map["GL_OES_shader_multisample_interpolation"] = enableableExtension(&Extensions::multisampleInterpolationOES);
map["GL_NV_robustness_video_memory_purge"] = esOnlyExtension(&Extensions::robustnessVideoMemoryPurgeNV);
map["GL_ANGLE_get_tex_level_parameter"] = enableableExtension(&Extensions::getTexLevelParameterANGLE);
// GLES1 extensions

Просмотреть файл

@ -654,6 +654,9 @@ struct Extensions
// GL_OES_sample_shading
bool sampleShadingOES = false;
// OES_shader_multisample_interpolation
bool multisampleInterpolationOES = false;
// GL_NV_robustness_video_memory_purge
bool robustnessVideoMemoryPurgeNV = false;
@ -746,6 +749,10 @@ struct Caps
// be GLint instead of GLuint and call LimitToInt() to ensure
// they will not overflow.
GLfloat minInterpolationOffset = 0;
GLfloat maxInterpolationOffset = 0;
GLint subPixelInterpolationOffsetBits = 0;
// ES 3.1 (April 29, 2015) 20.39: implementation dependent values
GLint64 maxElementIndex = 0;
GLint max3DTextureSize = 0;

Просмотреть файл

@ -110,7 +110,8 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const State &state, egl::Disp
mResources.ANGLE_multi_draw = extensions.multiDraw;
mResources.ANGLE_base_vertex_base_instance = extensions.baseVertexBaseInstance;
mResources.APPLE_clip_distance = extensions.clipDistanceAPPLE;
// OES_shader_multisample_interpolation
mResources.OES_shader_multisample_interpolation = extensions.multisampleInterpolationOES;
// TODO: use shader precision caps to determine if high precision is supported?
mResources.FragmentPrecisionHigh = 1;
mResources.EXT_frag_depth = extensions.fragDepth;

Просмотреть файл

@ -1419,6 +1419,12 @@ void Context::getFloatvImpl(GLenum pname, GLfloat *params) const
case GL_MAX_TEXTURE_LOD_BIAS:
*params = mState.mCaps.maxLODBias;
break;
case GL_MIN_FRAGMENT_INTERPOLATION_OFFSET:
*params = mState.mCaps.minInterpolationOffset;
break;
case GL_MAX_FRAGMENT_INTERPOLATION_OFFSET:
*params = mState.mCaps.maxInterpolationOffset;
break;
default:
mState.getFloatv(pname, params);
break;
@ -1850,7 +1856,10 @@ void Context::getIntegervImpl(GLenum pname, GLint *params) const
case GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT:
*params = mState.mExtensions.maxDualSourceDrawBuffers;
break;
// OES_shader_multisample_interpolation
case GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES:
*params = mState.mCaps.subPixelInterpolationOffsetBits;
break;
default:
ANGLE_CONTEXT_TRY(mState.getIntegerv(this, pname, params));
break;

Просмотреть файл

@ -3567,6 +3567,7 @@ bool GetQueryParameterInfo(const State &glState,
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
case GL_UNPACK_IMAGE_HEIGHT:
case GL_UNPACK_SKIP_IMAGES:
case GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES:
{
*type = GL_INT;
*numParams = 1;
@ -3595,6 +3596,8 @@ bool GetQueryParameterInfo(const State &glState,
}
case GL_MAX_TEXTURE_LOD_BIAS:
case GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES:
case GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES:
{
*type = GL_FLOAT;
*numParams = 1;

Просмотреть файл

@ -435,6 +435,9 @@ void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking,
case sh::INTERPOLATION_CENTROID:
hlslStream << " centroid ";
break;
case sh::INTERPOLATION_SAMPLE:
hlslStream << " sample ";
break;
default:
UNREACHABLE();
}

Просмотреть файл

@ -272,7 +272,29 @@ void RendererVk::ensureCapsInitialized() const
// VkPipelineMultisampleStateCreateInfo structure must be set to VK_FALSE and the
// minSampleShading member is ignored. This also specifies whether shader modules can declare
// the SampleRateShading capability
mNativeExtensions.sampleShadingOES = (mPhysicalDeviceFeatures.sampleRateShading == VK_TRUE);
bool supportSampleRateShading = (mPhysicalDeviceFeatures.sampleRateShading == VK_TRUE);
mNativeExtensions.sampleShadingOES = supportSampleRateShading;
mNativeCaps.minInterpolationOffset = limitsVk.minInterpolationOffset;
mNativeCaps.maxInterpolationOffset = limitsVk.maxInterpolationOffset;
mNativeCaps.subPixelInterpolationOffsetBits = limitsVk.subPixelInterpolationOffsetBits;
// From the Vulkan spec:
//
// > The values minInterpolationOffset and maxInterpolationOffset describe the closed interval
// > of supported interpolation offsets : [ minInterpolationOffset, maxInterpolationOffset ].
// > The ULP is determined by subPixelInterpolationOffsetBits. If
// > subPixelInterpolationOffsetBits is 4, this provides increments of(1 / 2^4) = 0.0625, and
// > thus the range of supported interpolation offsets would be[-0.5, 0.4375]
//
// OES_shader_multisample_interpolation requires a maximum value of -0.5 for
// MIN_FRAGMENT_INTERPOLATION_OFFSET_OES and minimum 0.5 for
// MAX_FRAGMENT_INTERPOLATION_OFFSET_OES. Vulkan has an identical limit for
// minInterpolationOffset, but it's limit for maxInterpolationOffset is 0.5-(1/ULP).
// OES_shader_multisample_interpolation is therefore only supported if
// maxInterpolationOffset is at least 0.5.
mNativeExtensions.multisampleInterpolationOES =
supportSampleRateShading && (mNativeCaps.maxInterpolationOffset >= 0.5);
// https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html
mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1;

Просмотреть файл

@ -187,6 +187,12 @@
// Cannot create 2D (array) view of 3D texture.
3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL
// Conflict between "interpolateAtOffset()" and the viewport transformation for a default framebuffer
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.no_qualifiers.default_framebuffer = FAIL
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.centroid_qualifier.default_framebuffer = FAIL
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.sample_qualifier.default_framebuffer = FAIL
3589 VULKAN : dEQP-GLES31.functional.shaders.multisample_interpolation.interpolate_at_offset.array_element.default_framebuffer = FAIL
////
//// Android (i.e. Pixel*) Vulkan expectations
////