Add support for GL_EXT_shared_memory_block
Uses SPV_KHR_workgroup_memory_explicit_layout. Note that if GL_EXT_scalar_block_layout is enabled, Workgroup blocks can also use scalar layout.
This commit is contained in:
parent
3785ddd59a
commit
4bfbf62794
33 changed files with 822 additions and 8 deletions
|
|
@ -87,6 +87,10 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b
|
|||
globalInputDefaults.clear();
|
||||
globalOutputDefaults.clear();
|
||||
|
||||
globalSharedDefaults.clear();
|
||||
globalSharedDefaults.layoutMatrix = ElmColumnMajor;
|
||||
globalSharedDefaults.layoutPacking = ElpStd430;
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
// "Shaders in the transform
|
||||
// feedback capturing mode have an initial global default of
|
||||
|
|
@ -6033,12 +6037,28 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type)
|
|||
}
|
||||
}
|
||||
|
||||
static bool storageCanHaveLayoutInBlock(const enum TStorageQualifier storage)
|
||||
{
|
||||
switch (storage) {
|
||||
case EvqUniform:
|
||||
case EvqBuffer:
|
||||
case EvqShared:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Do layout error checking that can be done within a layout qualifier proper, not needing to know
|
||||
// if there are blocks, atomic counters, variables, etc.
|
||||
void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier& qualifier)
|
||||
{
|
||||
if (qualifier.storage == EvqShared && qualifier.hasLayout())
|
||||
error(loc, "cannot apply layout qualifiers to a shared variable", "shared", "");
|
||||
if (qualifier.storage == EvqShared && qualifier.hasLayout()) {
|
||||
if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4) {
|
||||
error(loc, "shared block requires at least SPIR-V 1.4", "shared block", "");
|
||||
}
|
||||
profileRequires(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shared_memory_block, "shared block");
|
||||
}
|
||||
|
||||
// "It is a compile-time error to use *component* without also specifying the location qualifier (order does not matter)."
|
||||
if (qualifier.hasComponent() && ! qualifier.hasLocation())
|
||||
|
|
@ -6121,7 +6141,7 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier
|
|||
error(loc, "can only be used on an output", "xfb layout qualifier", "");
|
||||
}
|
||||
if (qualifier.hasUniformLayout()) {
|
||||
if (! qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory()) {
|
||||
if (!storageCanHaveLayoutInBlock(qualifier.storage) && !qualifier.isTaskMemory()) {
|
||||
if (qualifier.hasMatrix() || qualifier.hasPacking())
|
||||
error(loc, "matrix or packing qualifiers can only be used on a uniform or buffer", "layout", "");
|
||||
if (qualifier.hasOffset() || qualifier.hasAlign())
|
||||
|
|
@ -7667,6 +7687,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con
|
|||
case EvqBuffer: defaultQualification = globalBufferDefaults; break;
|
||||
case EvqVaryingIn: defaultQualification = globalInputDefaults; break;
|
||||
case EvqVaryingOut: defaultQualification = globalOutputDefaults; break;
|
||||
case EvqShared: defaultQualification = globalSharedDefaults; break;
|
||||
default: defaultQualification.clear(); break;
|
||||
}
|
||||
|
||||
|
|
@ -7930,6 +7951,12 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q
|
|||
error(loc, "output blocks cannot be used in a task shader", "out", "");
|
||||
}
|
||||
break;
|
||||
case EvqShared:
|
||||
if (spvVersion.spv > 0 && spvVersion.spv < EShTargetSpv_1_4) {
|
||||
error(loc, "shared block requires at least SPIR-V 1.4", "shared block", "");
|
||||
}
|
||||
profileRequires(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shared_memory_block, "shared block");
|
||||
break;
|
||||
#ifndef GLSLANG_WEB
|
||||
case EvqPayload:
|
||||
profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "rayPayloadNV block");
|
||||
|
|
@ -8088,7 +8115,7 @@ void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList)
|
|||
//
|
||||
void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typeList)
|
||||
{
|
||||
if (!qualifier.isUniformOrBuffer() && !qualifier.isTaskMemory())
|
||||
if (!storageCanHaveLayoutInBlock(qualifier.storage) && !qualifier.isTaskMemory())
|
||||
return;
|
||||
if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430 && qualifier.layoutPacking != ElpScalar)
|
||||
return;
|
||||
|
|
@ -8602,8 +8629,14 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con
|
|||
}
|
||||
#endif
|
||||
break;
|
||||
case EvqShared:
|
||||
if (qualifier.hasMatrix())
|
||||
globalSharedDefaults.layoutMatrix = qualifier.layoutMatrix;
|
||||
if (qualifier.hasPacking())
|
||||
globalSharedDefaults.layoutPacking = qualifier.layoutPacking;
|
||||
break;
|
||||
default:
|
||||
error(loc, "default qualifier requires 'uniform', 'buffer', 'in', or 'out' storage qualification", "", "");
|
||||
error(loc, "default qualifier requires 'uniform', 'buffer', 'in', 'out' or 'shared' storage qualification", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -485,6 +485,7 @@ protected:
|
|||
TQualifier globalUniformDefaults;
|
||||
TQualifier globalInputDefaults;
|
||||
TQualifier globalOutputDefaults;
|
||||
TQualifier globalSharedDefaults;
|
||||
TString currentCaller; // name of last function body entered (not valid when at global scope)
|
||||
#ifndef GLSLANG_WEB
|
||||
int* atomicUintOffsets; // to become an array of the right size to hold an offset per binding point
|
||||
|
|
|
|||
|
|
@ -331,6 +331,7 @@ void TParseVersions::initializeExtensionBehavior()
|
|||
extensionBehavior[E_GL_EXT_fragment_shading_rate] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_shader_image_int64] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_terminate_invocation] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_shared_memory_block] = EBhDisable;
|
||||
|
||||
// OVR extensions
|
||||
extensionBehavior[E_GL_OVR_multiview] = EBhDisable;
|
||||
|
|
@ -472,6 +473,7 @@ void TParseVersions::getPreamble(std::string& preamble)
|
|||
"#define GL_EXT_demote_to_helper_invocation 1\n"
|
||||
"#define GL_EXT_debug_printf 1\n"
|
||||
"#define GL_EXT_fragment_shading_rate 1\n"
|
||||
"#define GL_EXT_shared_memory_block 1\n"
|
||||
|
||||
// GL_KHR_shader_subgroup
|
||||
"#define GL_KHR_shader_subgroup_basic 1\n"
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ const char* const E_GL_EXT_shader_implicit_conversions = "GL_EXT_shader_imp
|
|||
const char* const E_GL_EXT_fragment_shading_rate = "GL_EXT_fragment_shading_rate";
|
||||
const char* const E_GL_EXT_shader_image_int64 = "GL_EXT_shader_image_int64";
|
||||
const char* const E_GL_EXT_null_initializer = "GL_EXT_null_initializer";
|
||||
const char* const E_GL_EXT_shared_memory_block = "GL_EXT_shared_memory_block";
|
||||
|
||||
// Arrays of extensions for the above viewportEXTs duplications
|
||||
|
||||
|
|
|
|||
|
|
@ -653,6 +653,25 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
|
|||
#endif
|
||||
}
|
||||
|
||||
void TIntermediate::sharedBlockCheck(TInfoSink& infoSink)
|
||||
{
|
||||
bool has_shared_block = false;
|
||||
bool has_shared_non_block = false;
|
||||
TIntermSequence& linkObjects = findLinkerObjects()->getSequence();
|
||||
for (size_t i = 0; i < linkObjects.size(); ++i) {
|
||||
const TType& type = linkObjects[i]->getAsTyped()->getType();
|
||||
const TQualifier& qualifier = type.getQualifier();
|
||||
if (qualifier.storage == glslang::EvqShared) {
|
||||
if (type.getBasicType() == glslang::EbtBlock)
|
||||
has_shared_block = true;
|
||||
else
|
||||
has_shared_non_block = true;
|
||||
}
|
||||
}
|
||||
if (has_shared_block && has_shared_non_block)
|
||||
error(infoSink, "cannot mix use of shared variables inside and outside blocks");
|
||||
}
|
||||
|
||||
//
|
||||
// Do final link-time error checking of a complete (merged) intermediate representation.
|
||||
// (Much error checking was done during merging).
|
||||
|
|
@ -778,6 +797,7 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
|
|||
error(infoSink, "post_depth_coverage requires early_fragment_tests");
|
||||
break;
|
||||
case EShLangCompute:
|
||||
sharedBlockCheck(infoSink);
|
||||
break;
|
||||
case EShLangRayGen:
|
||||
case EShLangIntersect:
|
||||
|
|
@ -810,6 +830,7 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled)
|
|||
case EShLangTaskNV:
|
||||
if (numTaskNVBlocks > 1)
|
||||
error(infoSink, "Only one taskNV interface block is allowed per shader");
|
||||
sharedBlockCheck(infoSink);
|
||||
break;
|
||||
default:
|
||||
error(infoSink, "Unknown Stage.");
|
||||
|
|
|
|||
|
|
@ -954,6 +954,7 @@ protected:
|
|||
void checkCallGraphCycles(TInfoSink&);
|
||||
void checkCallGraphBodies(TInfoSink&, bool keepUncalled);
|
||||
void inOutLocationCheck(TInfoSink&);
|
||||
void sharedBlockCheck(TInfoSink&);
|
||||
bool userOutputUsed() const;
|
||||
bool isSpecializationOperation(const TIntermOperator&) const;
|
||||
bool isNonuniformPropagating(TOperator) const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue